aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/api/wallet.cpp20
-rw-r--r--src/wallet/api/wallet.h1
-rw-r--r--src/wallet/node_rpc_proxy.cpp66
-rw-r--r--src/wallet/node_rpc_proxy.h14
-rw-r--r--src/wallet/ringdb.cpp117
-rw-r--r--src/wallet/ringdb.h9
-rw-r--r--src/wallet/wallet2.cpp881
-rw-r--r--src/wallet/wallet2.h261
-rw-r--r--src/wallet/wallet_errors.h18
-rw-r--r--src/wallet/wallet_rpc_server.cpp119
-rw-r--r--src/wallet/wallet_rpc_server.h5
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h46
12 files changed, 707 insertions, 850 deletions
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index bfd0e4aff..e9e9a4e67 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -369,7 +369,6 @@ void Wallet::error(const std::string &category, const std::string &str) {
WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds)
:m_wallet(nullptr)
, m_status(Wallet::Status_Ok)
- , m_trustedDaemon(false)
, m_wallet2Callback(nullptr)
, m_recoveringFromSeed(false)
, m_recoveringFromDevice(false)
@@ -1298,6 +1297,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin();
if (fake_outs_count == 0)
fake_outs_count = DEFAULT_MIXIN;
+ fake_outs_count = m_wallet->adjust_mixin(fake_outs_count);
uint32_t adjusted_priority = m_wallet->adjust_priority(static_cast<uint32_t>(priority));
@@ -1358,7 +1358,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
dsts.push_back(de);
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
adjusted_priority,
- extra, subaddr_account, subaddr_indices, m_trustedDaemon);
+ extra, subaddr_account, subaddr_indices);
} else {
// for the GUI, sweep_all (i.e. amount set as "(all)") will always sweep all the funds in all the addresses
if (subaddr_indices.empty())
@@ -1368,7 +1368,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
}
transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */,
adjusted_priority,
- extra, subaddr_account, subaddr_indices, m_trustedDaemon);
+ extra, subaddr_account, subaddr_indices);
}
if (multisig().isMultisig) {
@@ -1381,8 +1381,8 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
setStatusError(tr("no connection to daemon. Please make sure daemon is running."));
} catch (const tools::error::wallet_rpc_error& e) {
setStatusError(tr("RPC error: ") + e.to_string());
- } catch (const tools::error::get_random_outs_error &e) {
- setStatusError((boost::format(tr("failed to get random outputs to mix: %s")) % e.what()).str());
+ } catch (const tools::error::get_outs_error &e) {
+ setStatusError((boost::format(tr("failed to get outputs to mix: %s")) % e.what()).str());
} catch (const tools::error::not_enough_unlocked_money& e) {
std::ostringstream writer;
@@ -1454,7 +1454,7 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
do {
try {
- transaction->m_pending_tx = m_wallet->create_unmixable_sweep_transactions(m_trustedDaemon);
+ transaction->m_pending_tx = m_wallet->create_unmixable_sweep_transactions();
} catch (const tools::error::daemon_busy&) {
// TODO: make it translatable with "tr"?
@@ -1463,8 +1463,8 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
setStatusError(tr("no connection to daemon. Please make sure daemon is running."));
} catch (const tools::error::wallet_rpc_error& e) {
setStatusError(tr("RPC error: ") + e.to_string());
- } catch (const tools::error::get_random_outs_error&) {
- setStatusError(tr("failed to get random outputs to mix"));
+ } catch (const tools::error::get_outs_error&) {
+ setStatusError(tr("failed to get outputs to mix"));
} catch (const tools::error::not_enough_unlocked_money& e) {
setStatusError("");
std::ostringstream writer;
@@ -1891,12 +1891,12 @@ Wallet::ConnectionStatus WalletImpl::connected() const
void WalletImpl::setTrustedDaemon(bool arg)
{
- m_trustedDaemon = arg;
+ m_wallet->set_trusted_daemon(arg);
}
bool WalletImpl::trustedDaemon() const
{
- return m_trustedDaemon;
+ return m_wallet->is_trusted_daemon();
}
bool WalletImpl::watchOnly() const
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 9218d3ad5..0f3b1ce04 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -219,7 +219,6 @@ private:
mutable std::string m_errorString;
std::string m_password;
TransactionHistoryImpl * m_history;
- bool m_trustedDaemon;
Wallet2CallbackImpl * m_wallet2Callback;
AddressBookImpl * m_addressBook;
SubaddressImpl * m_subaddress;
diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp
index 2072495cd..21f75371b 100644
--- a/src/wallet/node_rpc_proxy.cpp
+++ b/src/wallet/node_rpc_proxy.cpp
@@ -50,12 +50,13 @@ void NodeRPCProxy::invalidate()
m_height = 0;
for (size_t n = 0; n < 256; ++n)
m_earliest_height[n] = 0;
- m_dynamic_per_kb_fee_estimate = 0;
- m_dynamic_per_kb_fee_estimate_cached_height = 0;
- m_dynamic_per_kb_fee_estimate_grace_blocks = 0;
+ m_dynamic_base_fee_estimate = 0;
+ m_dynamic_base_fee_estimate_cached_height = 0;
+ m_dynamic_base_fee_estimate_grace_blocks = 0;
+ m_fee_quantization_mask = 1;
m_rpc_version = 0;
m_target_height = 0;
- m_block_size_limit = 0;
+ m_block_weight_limit = 0;
m_get_info_time = 0;
}
@@ -99,7 +100,7 @@ boost::optional<std::string> NodeRPCProxy::get_info() const
CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get target blockchain height");
m_height = resp_t.height;
m_target_height = resp_t.target_height;
- m_block_size_limit = resp_t.block_size_limit;
+ m_block_weight_limit = resp_t.block_weight_limit ? resp_t.block_weight_limit : resp_t.block_size_limit;
m_get_info_time = now;
}
return boost::optional<std::string>();
@@ -123,12 +124,12 @@ boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) c
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_block_size_limit(uint64_t &block_size_limit) const
+boost::optional<std::string> NodeRPCProxy::get_block_weight_limit(uint64_t &block_weight_limit) const
{
auto res = get_info();
if (res)
return res;
- block_size_limit = m_block_size_limit;
+ block_weight_limit = m_block_weight_limit;
return boost::optional<std::string>();
}
@@ -153,7 +154,7 @@ boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version,
return boost::optional<std::string>();
}
-boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const
+boost::optional<std::string> NodeRPCProxy::get_dynamic_base_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const
{
uint64_t height;
@@ -161,10 +162,10 @@ boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint6
if (result)
return result;
- if (m_dynamic_per_kb_fee_estimate_cached_height != height || m_dynamic_per_kb_fee_estimate_grace_blocks != grace_blocks)
+ if (m_dynamic_base_fee_estimate_cached_height != height || m_dynamic_base_fee_estimate_grace_blocks != grace_blocks)
{
- cryptonote::COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request req_t = AUTO_VAL_INIT(req_t);
- cryptonote::COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response resp_t = AUTO_VAL_INIT(resp_t);
+ cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request req_t = AUTO_VAL_INIT(req_t);
+ cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::response resp_t = AUTO_VAL_INIT(resp_t);
m_daemon_rpc_mutex.lock();
req_t.grace_blocks = grace_blocks;
@@ -173,12 +174,47 @@ boost::optional<std::string> NodeRPCProxy::get_dynamic_per_kb_fee_estimate(uint6
CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get fee estimate");
- m_dynamic_per_kb_fee_estimate = resp_t.fee;
- m_dynamic_per_kb_fee_estimate_cached_height = height;
- m_dynamic_per_kb_fee_estimate_grace_blocks = grace_blocks;
+ m_dynamic_base_fee_estimate = resp_t.fee;
+ m_dynamic_base_fee_estimate_cached_height = height;
+ m_dynamic_base_fee_estimate_grace_blocks = grace_blocks;
+ m_fee_quantization_mask = resp_t.quantization_mask;
}
- fee = m_dynamic_per_kb_fee_estimate;
+ fee = m_dynamic_base_fee_estimate;
+ return boost::optional<std::string>();
+}
+
+boost::optional<std::string> NodeRPCProxy::get_fee_quantization_mask(uint64_t &fee_quantization_mask) const
+{
+ uint64_t height;
+
+ boost::optional<std::string> result = get_height(height);
+ if (result)
+ return result;
+
+ if (m_dynamic_base_fee_estimate_cached_height != height)
+ {
+ cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::request req_t = AUTO_VAL_INIT(req_t);
+ cryptonote::COMMAND_RPC_GET_BASE_FEE_ESTIMATE::response resp_t = AUTO_VAL_INIT(resp_t);
+
+ m_daemon_rpc_mutex.lock();
+ req_t.grace_blocks = m_dynamic_base_fee_estimate_grace_blocks;
+ bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_fee_estimate", req_t, resp_t, m_http_client, rpc_timeout);
+ m_daemon_rpc_mutex.unlock();
+ CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
+ CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
+ CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get fee estimate");
+ m_dynamic_base_fee_estimate = resp_t.fee;
+ m_dynamic_base_fee_estimate_cached_height = height;
+ m_fee_quantization_mask = resp_t.quantization_mask;
+ }
+
+ fee_quantization_mask = m_fee_quantization_mask;
+ if (fee_quantization_mask == 0)
+ {
+ MERROR("Fee quantization mask is 0, forcing to 1");
+ fee_quantization_mask = 1;
+ }
return boost::optional<std::string>();
}
diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h
index 8a65884f7..65f13eaaa 100644
--- a/src/wallet/node_rpc_proxy.h
+++ b/src/wallet/node_rpc_proxy.h
@@ -47,9 +47,10 @@ public:
boost::optional<std::string> get_height(uint64_t &height) const;
void set_height(uint64_t h);
boost::optional<std::string> get_target_height(uint64_t &height) const;
- boost::optional<std::string> get_block_size_limit(uint64_t &block_size_limit) const;
+ boost::optional<std::string> get_block_weight_limit(uint64_t &block_weight_limit) const;
boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height) const;
- boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const;
+ boost::optional<std::string> get_dynamic_base_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const;
+ boost::optional<std::string> get_fee_quantization_mask(uint64_t &fee_quantization_mask) const;
private:
boost::optional<std::string> get_info() const;
@@ -59,12 +60,13 @@ private:
mutable uint64_t m_height;
mutable uint64_t m_earliest_height[256];
- mutable uint64_t m_dynamic_per_kb_fee_estimate;
- mutable uint64_t m_dynamic_per_kb_fee_estimate_cached_height;
- mutable uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks;
+ mutable uint64_t m_dynamic_base_fee_estimate;
+ mutable uint64_t m_dynamic_base_fee_estimate_cached_height;
+ mutable uint64_t m_dynamic_base_fee_estimate_grace_blocks;
+ mutable uint64_t m_fee_quantization_mask;
mutable uint32_t m_rpc_version;
mutable uint64_t m_target_height;
- mutable uint64_t m_block_size_limit;
+ mutable uint64_t m_block_weight_limit;
mutable time_t m_get_info_time;
};
diff --git a/src/wallet/ringdb.cpp b/src/wallet/ringdb.cpp
index 3f2634c8b..e9fc6866d 100644
--- a/src/wallet/ringdb.cpp
+++ b/src/wallet/ringdb.cpp
@@ -55,6 +55,13 @@ static int compare_hash32(const MDB_val *a, const MDB_val *b)
return 0;
}
+static int compare_uint64(const MDB_val *a, const MDB_val *b)
+{
+ const uint64_t va = *(const uint64_t*) a->mv_data;
+ const uint64_t vb = *(const uint64_t*) b->mv_data;
+ return va < vb ? -1 : va > vb;
+}
+
static std::string compress_ring(const std::vector<uint64_t> &ring)
{
std::string s;
@@ -146,7 +153,7 @@ static int resize_env(MDB_env *env, const char *db_path, size_t needed)
MDB_stat mst;
int ret;
- needed = std::max(needed, (size_t)(2ul * 1024 * 1024)); // at least 2 MB
+ needed = std::max(needed, (size_t)(100ul * 1024 * 1024)); // at least 100 MB
ret = mdb_env_info(env, &mei);
if (ret)
@@ -217,9 +224,9 @@ ringdb::ringdb(std::string filename, const std::string &genesis):
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr)));
mdb_set_compare(txn, dbi_rings, compare_hash32);
- dbr = mdb_dbi_open(txn, ("blackballs-" + genesis).c_str(), MDB_CREATE | MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, &dbi_blackballs);
+ dbr = mdb_dbi_open(txn, ("blackballs2-" + genesis).c_str(), MDB_CREATE | MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, &dbi_blackballs);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr)));
- mdb_set_dupsort(txn, dbi_blackballs, compare_hash32);
+ mdb_set_dupsort(txn, dbi_blackballs, compare_uint64);
dbr = mdb_txn_commit(txn);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn creating/opening database: " + std::string(mdb_strerror(dbr)));
@@ -374,7 +381,7 @@ bool ringdb::set_ring(const crypto::chacha_key &chacha_key, const crypto::key_im
return true;
}
-bool ringdb::blackball_worker(const crypto::public_key &output, int op)
+bool ringdb::blackball_worker(const std::vector<std::pair<uint64_t, uint64_t>> &outputs, int op)
{
MDB_txn *txn;
MDB_cursor *cursor;
@@ -382,49 +389,61 @@ bool ringdb::blackball_worker(const crypto::public_key &output, int op)
bool tx_active = false;
bool ret = true;
- dbr = resize_env(env, filename.c_str(), 32 * 2); // a pubkey, and some slack
+ THROW_WALLET_EXCEPTION_IF(outputs.size() > 1 && op == BLACKBALL_QUERY, tools::error::wallet_internal_error, "Blackball query only makes sense for a single output");
+
+ dbr = resize_env(env, filename.c_str(), 32 * 2 * outputs.size()); // a pubkey, and some slack
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to set env map size: " + std::string(mdb_strerror(dbr)));
dbr = mdb_txn_begin(env, NULL, 0, &txn);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr)));
epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);});
tx_active = true;
- MDB_val key = zerokeyval;
- MDB_val data;
- data.mv_data = (void*)&output;
- data.mv_size = sizeof(output);
- switch (op)
+ MDB_val key, data;
+ for (const std::pair<uint64_t, uint64_t> &output: outputs)
+ {
+ key.mv_data = (void*)&output.first;
+ key.mv_size = sizeof(output.first);
+ data.mv_data = (void*)&output.second;
+ data.mv_size = sizeof(output.second);
+
+ switch (op)
+ {
+ case BLACKBALL_BLACKBALL:
+ MDEBUG("Blackballing output " << output.first << "/" << output.second);
+ dbr = mdb_put(txn, dbi_blackballs, &key, &data, MDB_APPENDDUP);
+ if (dbr == MDB_KEYEXIST)
+ dbr = 0;
+ break;
+ case BLACKBALL_UNBLACKBALL:
+ MDEBUG("Unblackballing output " << output.first << "/" << output.second);
+ dbr = mdb_del(txn, dbi_blackballs, &key, &data);
+ if (dbr == MDB_NOTFOUND)
+ dbr = 0;
+ break;
+ case BLACKBALL_QUERY:
+ dbr = mdb_cursor_open(txn, dbi_blackballs, &cursor);
+ THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create cursor for blackballs table: " + std::string(mdb_strerror(dbr)));
+ dbr = mdb_cursor_get(cursor, &key, &data, MDB_GET_BOTH);
+ THROW_WALLET_EXCEPTION_IF(dbr && dbr != MDB_NOTFOUND, tools::error::wallet_internal_error, "Failed to lookup in blackballs table: " + std::string(mdb_strerror(dbr)));
+ ret = dbr != MDB_NOTFOUND;
+ if (dbr == MDB_NOTFOUND)
+ dbr = 0;
+ mdb_cursor_close(cursor);
+ break;
+ case BLACKBALL_CLEAR:
+ break;
+ default:
+ THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Invalid blackball op");
+ }
+ THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to query blackballs table: " + std::string(mdb_strerror(dbr)));
+ }
+
+ if (op == BLACKBALL_CLEAR)
{
- case BLACKBALL_BLACKBALL:
- MDEBUG("Blackballing output " << output);
- dbr = mdb_put(txn, dbi_blackballs, &key, &data, MDB_NODUPDATA);
- if (dbr == MDB_KEYEXIST)
- dbr = 0;
- break;
- case BLACKBALL_UNBLACKBALL:
- MDEBUG("Unblackballing output " << output);
- dbr = mdb_del(txn, dbi_blackballs, &key, &data);
- if (dbr == MDB_NOTFOUND)
- dbr = 0;
- break;
- case BLACKBALL_QUERY:
- dbr = mdb_cursor_open(txn, dbi_blackballs, &cursor);
- THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to create cursor for blackballs table: " + std::string(mdb_strerror(dbr)));
- dbr = mdb_cursor_get(cursor, &key, &data, MDB_GET_BOTH);
- THROW_WALLET_EXCEPTION_IF(dbr && dbr != MDB_NOTFOUND, tools::error::wallet_internal_error, "Failed to lookup in blackballs table: " + std::string(mdb_strerror(dbr)));
- ret = dbr != MDB_NOTFOUND;
- if (dbr == MDB_NOTFOUND)
- dbr = 0;
- mdb_cursor_close(cursor);
- break;
- case BLACKBALL_CLEAR:
- dbr = mdb_drop(txn, dbi_blackballs, 0);
- break;
- default:
- THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Invalid blackball op");
+ dbr = mdb_drop(txn, dbi_blackballs, 0);
+ THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to clear blackballs table: " + std::string(mdb_strerror(dbr)));
}
- THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to query blackballs table: " + std::string(mdb_strerror(dbr)));
dbr = mdb_txn_commit(txn);
THROW_WALLET_EXCEPTION_IF(dbr, tools::error::wallet_internal_error, "Failed to commit txn blackballing output to database: " + std::string(mdb_strerror(dbr)));
@@ -432,24 +451,32 @@ bool ringdb::blackball_worker(const crypto::public_key &output, int op)
return ret;
}
-bool ringdb::blackball(const crypto::public_key &output)
+bool ringdb::blackball(const std::vector<std::pair<uint64_t, uint64_t>> &outputs)
+{
+ return blackball_worker(outputs, BLACKBALL_BLACKBALL);
+}
+
+bool ringdb::blackball(const std::pair<uint64_t, uint64_t> &output)
{
- return blackball_worker(output, BLACKBALL_BLACKBALL);
+ std::vector<std::pair<uint64_t, uint64_t>> outputs(1, output);
+ return blackball_worker(outputs, BLACKBALL_BLACKBALL);
}
-bool ringdb::unblackball(const crypto::public_key &output)
+bool ringdb::unblackball(const std::pair<uint64_t, uint64_t> &output)
{
- return blackball_worker(output, BLACKBALL_UNBLACKBALL);
+ std::vector<std::pair<uint64_t, uint64_t>> outputs(1, output);
+ return blackball_worker(outputs, BLACKBALL_UNBLACKBALL);
}
-bool ringdb::blackballed(const crypto::public_key &output)
+bool ringdb::blackballed(const std::pair<uint64_t, uint64_t> &output)
{
- return blackball_worker(output, BLACKBALL_QUERY);
+ std::vector<std::pair<uint64_t, uint64_t>> outputs(1, output);
+ return blackball_worker(outputs, BLACKBALL_QUERY);
}
bool ringdb::clear_blackballs()
{
- return blackball_worker(crypto::public_key(), BLACKBALL_CLEAR);
+ return blackball_worker(std::vector<std::pair<uint64_t, uint64_t>>(), BLACKBALL_CLEAR);
}
}
diff --git a/src/wallet/ringdb.h b/src/wallet/ringdb.h
index 6b4bce124..7b448b0d7 100644
--- a/src/wallet/ringdb.h
+++ b/src/wallet/ringdb.h
@@ -49,13 +49,14 @@ namespace tools
bool get_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
bool set_ring(const crypto::chacha_key &chacha_key, const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
- bool blackball(const crypto::public_key &output);
- bool unblackball(const crypto::public_key &output);
- bool blackballed(const crypto::public_key &output);
+ bool blackball(const std::pair<uint64_t, uint64_t> &output);
+ bool blackball(const std::vector<std::pair<uint64_t, uint64_t>> &outputs);
+ bool unblackball(const std::pair<uint64_t, uint64_t> &output);
+ bool blackballed(const std::pair<uint64_t, uint64_t> &output);
bool clear_blackballs();
private:
- bool blackball_worker(const crypto::public_key &output, int op);
+ bool blackball_worker(const std::vector<std::pair<uint64_t, uint64_t>> &outputs, int op);
private:
std::string filename;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 96b77a7a6..0b1c9d995 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -84,8 +84,8 @@ using namespace cryptonote;
// used to choose when to stop adding outputs to a tx
#define APPROXIMATE_INPUT_BYTES 80
-// used to target a given block size (additional outputs may be added on top to build fee)
-#define TX_SIZE_TARGET(bytes) (bytes*2/3)
+// used to target a given block weight (additional outputs may be added on top to build fee)
+#define TX_WEIGHT_TARGET(bytes) (bytes*2/3)
// arbitrary, used to generate different hashes from the same input
#define CHACHA8_KEY_TAIL 0x8c
@@ -140,6 +140,8 @@ namespace
struct options {
const command_line::arg_descriptor<std::string> daemon_address = {"daemon-address", tools::wallet2::tr("Use daemon instance at <host>:<port>"), ""};
const command_line::arg_descriptor<std::string> daemon_host = {"daemon-host", tools::wallet2::tr("Use daemon instance at host <arg> instead of localhost"), ""};
+ const command_line::arg_descriptor<bool> trusted_daemon = {"trusted-daemon", tools::wallet2::tr("Enable commands which rely on a trusted daemon"), false};
+ const command_line::arg_descriptor<bool> untrusted_daemon = {"untrusted-daemon", tools::wallet2::tr("Disable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<std::string> password = {"password", tools::wallet2::tr("Wallet password (escape/quote as needed)"), "", true};
const command_line::arg_descriptor<std::string> password_file = {"password-file", tools::wallet2::tr("Wallet password file"), "", true};
const command_line::arg_descriptor<int> daemon_port = {"daemon-port", tools::wallet2::tr("Use daemon instance at port <arg> instead of 18081"), 0};
@@ -181,19 +183,21 @@ uint64_t calculate_fee(uint64_t fee_per_kb, size_t bytes, uint64_t fee_multiplie
return kB * fee_per_kb * fee_multiplier;
}
-uint64_t calculate_fee(uint64_t fee_per_kb, const cryptonote::blobdata &blob, uint64_t fee_multiplier)
+uint64_t calculate_fee_from_weight(uint64_t base_fee, uint64_t weight, uint64_t fee_multiplier, uint64_t fee_quantization_mask)
{
- return calculate_fee(fee_per_kb, blob.size(), fee_multiplier);
+ uint64_t fee = weight * base_fee * fee_multiplier;
+ fee = (fee + fee_quantization_mask - 1) / fee_quantization_mask * fee_quantization_mask;
+ return fee;
}
-std::string get_size_string(size_t sz)
+std::string get_weight_string(size_t weight)
{
- return std::to_string(sz) + " bytes (" + std::to_string((sz + 1023) / 1024) + " kB)";
+ return std::to_string(weight) + " weight";
}
-std::string get_size_string(const cryptonote::blobdata &tx)
+std::string get_weight_string(const cryptonote::transaction &tx, size_t blob_size)
{
- return get_size_string(tx.size());
+ return get_weight_string(get_transaction_weight(tx, blob_size));
}
std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variables_map& vm, bool rpc, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter)
@@ -236,8 +240,29 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl
if (daemon_address.empty())
daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port);
+ boost::optional<bool> trusted_daemon;
+ if (!command_line::is_arg_defaulted(vm, opts.trusted_daemon) || !command_line::is_arg_defaulted(vm, opts.untrusted_daemon))
+ trusted_daemon = command_line::get_arg(vm, opts.trusted_daemon) && !command_line::get_arg(vm, opts.untrusted_daemon);
+ THROW_WALLET_EXCEPTION_IF(!command_line::is_arg_defaulted(vm, opts.trusted_daemon) && !command_line::is_arg_defaulted(vm, opts.untrusted_daemon),
+ tools::error::wallet_internal_error, tools::wallet2::tr("--trusted-daemon and --untrusted-daemon are both seen, assuming untrusted"));
+
+ // set --trusted-daemon if local and not overridden
+ if (!trusted_daemon)
+ {
+ try
+ {
+ trusted_daemon = false;
+ if (tools::is_local_address(daemon_address))
+ {
+ MINFO(tr("Daemon is local, assuming trusted"));
+ trusted_daemon = true;
+ }
+ }
+ catch (const std::exception &e) { }
+ }
+
std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, kdf_rounds));
- wallet->init(rpc, std::move(daemon_address), std::move(login));
+ wallet->init(rpc, std::move(daemon_address), std::move(login), 0, false, *trusted_daemon);
boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir);
wallet->set_ring_database(ringdb_path.string());
return wallet;
@@ -553,7 +578,12 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
// rangeSigs
if (bulletproof)
- size += ((2*6 + 4 + 5)*32 + 3) * n_outputs;
+ {
+ size_t log_padded_outputs = 0;
+ while ((1<<log_padded_outputs) < n_outputs)
+ ++log_padded_outputs;
+ size += (2 * (6 + log_padded_outputs) + 4 + 5) * 32 + 3;
+ }
else
size += (2*64*32+32+64*32) * n_outputs;
@@ -572,23 +602,63 @@ size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra
// txnFee
size += 4;
- LOG_PRINT_L2("estimated rct tx size for " << n_inputs << " with ring size " << (mixin+1) << " and " << n_outputs << ": " << size << " (" << ((32 * n_inputs/*+1*/) + 2 * 32 * (mixin+1) * n_inputs + 32 * n_outputs) << " saved)");
+ LOG_PRINT_L2("estimated " << (bulletproof ? "bulletproof" : "borromean") << " rct tx size for " << n_inputs << " inputs with ring size " << (mixin+1) << " and " << n_outputs << " outputs: " << size << " (" << ((32 * n_inputs/*+1*/) + 2 * 32 * (mixin+1) * n_inputs + 32 * n_outputs) << " saved)");
return size;
}
size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof)
{
if (use_rct)
- return estimate_rct_tx_size(n_inputs, mixin, n_outputs + 1, extra_size, bulletproof);
+ return estimate_rct_tx_size(n_inputs, mixin, n_outputs, extra_size, bulletproof);
else
return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size;
}
+uint64_t estimate_tx_weight(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof)
+{
+ size_t size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof);
+ if (use_rct && bulletproof && n_outputs > 2)
+ {
+ const uint64_t bp_base = 368;
+ size_t log_padded_outputs = 2;
+ while ((1<<log_padded_outputs) < n_outputs)
+ ++log_padded_outputs;
+ uint64_t nlr = 2 * (6 + log_padded_outputs);
+ const uint64_t bp_size = 32 * (9 + nlr);
+ const uint64_t bp_clawback = (bp_base * (1<<log_padded_outputs) - bp_size) * 4 / 5;
+ MDEBUG("clawback on size " << size << ": " << bp_clawback);
+ size += bp_clawback;
+ }
+ return size;
+}
+
uint8_t get_bulletproof_fork()
{
return 8;
}
+uint64_t estimate_fee(bool use_per_byte_fee, bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof, uint64_t base_fee, uint64_t fee_multiplier, uint64_t fee_quantization_mask)
+{
+ if (use_per_byte_fee)
+ {
+ const size_t estimated_tx_weight = estimate_tx_weight(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof);
+ return calculate_fee_from_weight(base_fee, estimated_tx_weight, fee_multiplier, fee_quantization_mask);
+ }
+ else
+ {
+ const size_t estimated_tx_size = estimate_tx_size(use_rct, n_inputs, mixin, n_outputs, extra_size, bulletproof);
+ return calculate_fee(base_fee, estimated_tx_size, fee_multiplier);
+ }
+}
+
+uint64_t calculate_fee(bool use_per_byte_fee, const cryptonote::transaction &tx, size_t blob_size, uint64_t base_fee, uint64_t fee_multiplier, uint64_t fee_quantization_mask)
+{
+ if (use_per_byte_fee)
+ return calculate_fee_from_weight(base_fee, cryptonote::get_transaction_weight(tx, blob_size), fee_multiplier, fee_quantization_mask);
+ else
+ return calculate_fee(base_fee, blob_size, fee_multiplier);
+}
+
crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx, hw::device &hwdev)
{
crypto::hash8 payment_id8 = null_hash8;
@@ -680,6 +750,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds):
m_multisig_rescan_k(NULL),
m_run(true),
m_callback(0),
+ m_trusted_daemon(false),
m_nettype(nettype),
m_always_confirm_transfers(true),
m_print_ring_members(false),
@@ -745,6 +816,8 @@ void wallet2::init_options(boost::program_options::options_description& desc_par
const options opts{};
command_line::add_arg(desc_params, opts.daemon_address);
command_line::add_arg(desc_params, opts.daemon_host);
+ command_line::add_arg(desc_params, opts.trusted_daemon);
+ command_line::add_arg(desc_params, opts.untrusted_daemon);
command_line::add_arg(desc_params, opts.password);
command_line::add_arg(desc_params, opts.password_file);
command_line::add_arg(desc_params, opts.daemon_port);
@@ -796,16 +869,17 @@ std::unique_ptr<wallet2> wallet2::make_dummy(const boost::program_options::varia
}
//----------------------------------------------------------------------------------------------------
-bool wallet2::init(bool rpc, std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, uint64_t upper_transaction_size_limit, bool ssl)
+bool wallet2::init(bool rpc, std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login, uint64_t upper_transaction_weight_limit, bool ssl, bool trusted_daemon)
{
m_rpc = rpc;
m_checkpoints.init_default_checkpoints(m_nettype);
if(m_http_client.is_connected())
m_http_client.disconnect();
m_is_initialized = true;
- m_upper_transaction_size_limit = upper_transaction_size_limit;
+ m_upper_transaction_weight_limit = upper_transaction_weight_limit;
m_daemon_address = std::move(daemon_address);
m_daemon_login = std::move(daemon_login);
+ m_trusted_daemon = trusted_daemon;
// When switching from light wallet to full wallet, we need to reset the height we got from lw node.
return m_http_client.set_server(get_daemon_address(), get_daemon_login(), ssl);
}
@@ -1115,10 +1189,9 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &
switch (rv.type)
{
case rct::RCTTypeSimple:
- case rct::RCTTypeSimpleBulletproof:
+ case rct::RCTTypeBulletproof:
return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev);
case rct::RCTTypeFull:
- case rct::RCTTypeFullBulletproof:
return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev);
default:
LOG_ERROR("Unsupported rct type: " << rv.type);
@@ -1808,34 +1881,7 @@ void wallet2::pull_blocks(uint64_t start_height, uint64_t &blocks_start_height,
cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::response res = AUTO_VAL_INIT(res);
req.block_ids = short_chain_history;
- uint32_t rpc_version;
- boost::optional<std::string> result = m_node_rpc_proxy.get_rpc_version(rpc_version);
- // no error
- if (!!result)
- {
- // empty string -> not connection
- THROW_WALLET_EXCEPTION_IF(result->empty(), tools::error::no_connection_to_daemon, "getversion");
- THROW_WALLET_EXCEPTION_IF(*result == CORE_RPC_STATUS_BUSY, tools::error::daemon_busy, "getversion");
- if (*result != CORE_RPC_STATUS_OK)
- {
- MDEBUG("Cannot determine daemon RPC version, not asking for pruned blocks");
- req.prune = false; // old daemon
- }
- }
- else
- {
- if (rpc_version >= MAKE_CORE_RPC_VERSION(1, 7))
- {
- MDEBUG("Daemon is recent enough, asking for pruned blocks");
- req.prune = true;
- }
- else
- {
- MDEBUG("Daemon is too old, not asking for pruned blocks");
- req.prune = false;
- }
- }
-
+ req.prune = true;
req.start_height = start_height;
req.no_miner_tx = m_refresh_type == RefreshNoCoinbase;
m_daemon_rpc_mutex.lock();
@@ -2021,9 +2067,11 @@ void wallet2::pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks
{
drop_from_short_history(short_chain_history, 3);
+ THROW_WALLET_EXCEPTION_IF(prev_blocks.size() != prev_parsed_blocks.size(), error::wallet_internal_error, "size mismatch");
+
// prepend the last 3 blocks, should be enough to guard against a block or two's reorg
std::vector<parsed_block>::const_reverse_iterator i = prev_parsed_blocks.rbegin();
- for (size_t n = 0; n < std::min((size_t)3, prev_blocks.size()); ++n)
+ for (size_t n = 0; n < std::min((size_t)3, prev_parsed_blocks.size()); ++n)
{
short_chain_history.push_front(i->hash);
++i;
@@ -2343,6 +2391,7 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height,
while (missing_blocks-- > 0)
m_blockchain.push_back(crypto::null_hash); // maybe a bit suboptimal, but deque won't do huge reallocs like vector
m_blockchain.push_back(m_checkpoints.get_points().at(checkpoint_height));
+ m_blockchain.trim(checkpoint_height);
short_chain_history.clear();
get_short_chain_history(short_chain_history);
}
@@ -2554,10 +2603,6 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
break;
}
- // switch to the new blocks from the daemon
- blocks_start_height = next_blocks_start_height;
- blocks = std::move(next_blocks);
- parsed_blocks = std::move(next_parsed_blocks);
first = false;
// handle error from async fetching thread
@@ -2565,6 +2610,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
{
throw std::runtime_error("proxy exception in refresh thread");
}
+
+ // switch to the new blocks from the daemon
+ blocks_start_height = next_blocks_start_height;
+ blocks = std::move(next_blocks);
+ parsed_blocks = std::move(next_parsed_blocks);
}
catch (const tools::error::password_needed&)
{
@@ -2656,6 +2706,7 @@ bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t>
req.amounts.push_back(0);
req.from_height = 0;
req.cumulative = true;
+ req.binary = true;
m_daemon_rpc_mutex.lock();
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req, res, m_http_client, rpc_timeout);
m_daemon_rpc_mutex.unlock();
@@ -3324,6 +3375,31 @@ void wallet2::decrypt_keys(const epee::wipeable_string &password)
decrypt_keys(key);
}
+void wallet2::setup_new_blockchain()
+{
+ cryptonote::block b;
+ generate_genesis(b);
+ m_blockchain.push_back(get_block_hash(b));
+ m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
+ add_subaddress_account(tr("Primary account"));
+}
+
+void wallet2::create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file)
+{
+ if (!wallet_.empty())
+ {
+ bool r = store_keys(m_keys_file, password, watch_only);
+ THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
+
+ if (create_address_file)
+ {
+ r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
+ if(!r) MERROR("String with address text not saved");
+ }
+ }
+}
+
+
/*!
* \brief Generates a wallet or restores one.
* \param wallet_ Name of wallet file
@@ -3388,6 +3464,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
for (const auto &msk: multisig_keys)
sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes);
THROW_WALLET_EXCEPTION_IF(!(rct::rct2sk(skey) == spend_secret_key), error::invalid_multisig_seed);
+ memwipe(&skey, sizeof(rct::key));
m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys);
m_account.finalize_multisig(spend_public_key);
@@ -3400,23 +3477,8 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_key_on_device = false;
setup_keys(password);
- if (!wallet_.empty())
- {
- bool r = store_keys(m_keys_file, password, false);
- THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
-
- if (m_nettype != MAINNET || create_address_file)
- {
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
- if(!r) MERROR("String with address text not saved");
- }
- }
-
- cryptonote::block b;
- generate_genesis(b);
- m_blockchain.push_back(get_block_hash(b));
- m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
- add_subaddress_account(tr("Primary account"));
+ create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
+ setup_new_blockchain();
if (!wallet_.empty())
store();
@@ -3460,23 +3522,9 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const epee::wip
m_refresh_from_block_height = estimate_blockchain_height();
}
- if (!wallet_.empty())
- {
- bool r = store_keys(m_keys_file, password, false);
- THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
+ create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
- if (m_nettype != MAINNET || create_address_file)
- {
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
- if(!r) MERROR("String with address text not saved");
- }
- }
-
- cryptonote::block b;
- generate_genesis(b);
- m_blockchain.push_back(get_block_hash(b));
- m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
- add_subaddress_account(tr("Primary account"));
+ setup_new_blockchain();
if (!wallet_.empty())
store();
@@ -3557,23 +3605,9 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_key_on_device = false;
setup_keys(password);
- if (!wallet_.empty())
- {
- bool r = store_keys(m_keys_file, password, true);
- THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
-
- if (m_nettype != MAINNET || create_address_file)
- {
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
- if(!r) MERROR("String with address text not saved");
- }
- }
+ create_keys_file(wallet_, true, password, m_nettype != MAINNET || create_address_file);
- cryptonote::block b;
- generate_genesis(b);
- m_blockchain.push_back(get_block_hash(b));
- m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
- add_subaddress_account(tr("Primary account"));
+ setup_new_blockchain();
if (!wallet_.empty())
store();
@@ -3611,23 +3645,9 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
m_key_on_device = false;
setup_keys(password);
- if (!wallet_.empty())
- {
- bool r = store_keys(m_keys_file, password, false);
- THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
-
- if (m_nettype != MAINNET || create_address_file)
- {
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
- if(!r) MERROR("String with address text not saved");
- }
- }
+ create_keys_file(wallet_, false, password, create_address_file);
- cryptonote::block b;
- generate_genesis(b);
- m_blockchain.push_back(get_block_hash(b));
- m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
- add_subaddress_account(tr("Primary account"));
+ setup_new_blockchain();
if (!wallet_.empty())
store();
@@ -3639,7 +3659,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
* \param password Password of wallet file
* \param device_name device string address
*/
-void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name)
+void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name, bool create_address_file)
{
clear();
prepare_file_names(wallet_);
@@ -3658,24 +3678,14 @@ void wallet2::restore(const std::string& wallet_, const epee::wipeable_string& p
m_multisig_signers.clear();
setup_keys(password);
- if (!wallet_.empty()) {
- bool r = store_keys(m_keys_file, password, false);
- THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
-
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
- if(!r) MERROR("String with address text not saved");
- }
- cryptonote::block b;
- generate_genesis(b);
- m_blockchain.push_back(get_block_hash(b));
+ create_keys_file(wallet_, false, password, m_nettype != MAINNET || create_address_file);
if (m_subaddress_lookahead_major == SUBADDRESS_LOOKAHEAD_MAJOR && m_subaddress_lookahead_minor == SUBADDRESS_LOOKAHEAD_MINOR)
{
// the default lookahead setting (50:200) is clearly too much for hardware wallet
m_subaddress_lookahead_major = 5;
m_subaddress_lookahead_minor = 20;
}
- m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
- add_subaddress_account(tr("Primary account"));
+ setup_new_blockchain();
if (!wallet_.empty()) {
store();
}
@@ -3750,6 +3760,7 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
MINFO("Creating multisig address...");
CHECK_AND_ASSERT_THROW_MES(m_account.make_multisig(view_skey, rct::rct2sk(spend_skey), rct::rct2pk(spend_pkey), multisig_keys),
"Failed to create multisig wallet due to bad keys");
+ memwipe(&spend_skey, sizeof(rct::key));
m_account_public_address = m_account.get_keys().m_account_address;
m_watch_only = false;
@@ -3770,23 +3781,9 @@ std::string wallet2::make_multisig(const epee::wipeable_string &password,
// re-encrypt keys
keys_reencryptor = epee::misc_utils::auto_scope_leave_caller();
- if (!m_wallet_file.empty())
- {
- bool r = store_keys(m_keys_file, password, false);
- THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
+ create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
- if (boost::filesystem::exists(m_wallet_file + ".address.txt"))
- {
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
- if(!r) MERROR("String with address text not saved");
- }
- }
-
- cryptonote::block b;
- generate_genesis(b);
- m_blockchain.push_back(get_block_hash(b));
- m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
- add_subaddress_account(tr("Primary account"));
+ setup_new_blockchain();
if (!m_wallet_file.empty())
store();
@@ -3888,17 +3885,7 @@ bool wallet2::finalize_multisig(const epee::wipeable_string &password, std::unor
// keys are encrypted again
keys_reencryptor = epee::misc_utils::auto_scope_leave_caller();
- if (!m_wallet_file.empty())
- {
- bool r = store_keys(m_keys_file, password, false);
- THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
-
- if (boost::filesystem::exists(m_wallet_file + ".address.txt"))
- {
- r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype));
- if(!r) MERROR("String with address text not saved");
- }
- }
+ create_keys_file(m_wallet_file, false, password, boost::filesystem::exists(m_wallet_file + ".address.txt"));
m_subaddresses.clear();
m_subaddress_labels.clear();
@@ -4709,12 +4696,7 @@ void wallet2::rescan_blockchain(bool refresh)
{
clear();
- cryptonote::block genesis;
- generate_genesis(genesis);
- crypto::hash genesis_hash = get_block_hash(genesis);
- m_blockchain.push_back(genesis_hash);
- m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx);
- add_subaddress_account(tr("Primary account"));
+ setup_new_blockchain();
if (refresh)
this->refresh(false);
@@ -4751,7 +4733,7 @@ bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t block_heig
uint64_t current_time = static_cast<uint64_t>(time(NULL));
// XXX: this needs to be fast, so we'd need to get the starting heights
// from the daemon to be correct once voting kicks in
- uint64_t v2height = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? (uint64_t)-1/*TODO*/ : 1009827;
+ uint64_t v2height = m_nettype == TESTNET ? 624634 : m_nettype == STAGENET ? 32000 : 1009827;
uint64_t leeway = block_height < v2height ? CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 : CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2;
if(current_time + leeway >= unlock_time)
return true;
@@ -4901,7 +4883,7 @@ size_t wallet2::pop_best_value(std::vector<size_t> &unused_indices, const std::v
// returns:
// direct return: amount of money found
// modified reference: selected_transfers, a list of iterators/indices of input sources
-uint64_t wallet2::select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers, bool trusted_daemon) const
+uint64_t wallet2::select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers) const
{
uint64_t found_money = 0;
selected_transfers.reserve(unused_transfers_indices.size());
@@ -4944,69 +4926,6 @@ void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t amo
}
//----------------------------------------------------------------------------------------------------
-void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outs_count, const std::vector<size_t> &unused_transfers_indices,
- uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon)
-{
- transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), tx, ptx, trusted_daemon);
-}
-//----------------------------------------------------------------------------------------------------
-void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outs_count, const std::vector<size_t> &unused_transfers_indices,
- uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, bool trusted_daemon)
-{
- cryptonote::transaction tx;
- pending_tx ptx;
- transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, tx, ptx, trusted_daemon);
-}
-
-namespace {
-// split_amounts(vector<cryptonote::tx_destination_entry> dsts, size_t num_splits)
-//
-// split amount for each dst in dsts into num_splits parts
-// and make num_splits new vector<crypt...> instances to hold these new amounts
-std::vector<std::vector<cryptonote::tx_destination_entry>> split_amounts(
- std::vector<cryptonote::tx_destination_entry> dsts, size_t num_splits)
-{
- std::vector<std::vector<cryptonote::tx_destination_entry>> retVal;
-
- if (num_splits <= 1)
- {
- retVal.push_back(dsts);
- return retVal;
- }
-
- // for each split required
- for (size_t i=0; i < num_splits; i++)
- {
- std::vector<cryptonote::tx_destination_entry> new_dsts;
-
- // for each destination
- for (size_t j=0; j < dsts.size(); j++)
- {
- cryptonote::tx_destination_entry de;
- uint64_t amount;
-
- amount = dsts[j].amount;
- amount = amount / num_splits;
-
- // if last split, add remainder
- if (i + 1 == num_splits)
- {
- amount += dsts[j].amount % num_splits;
- }
-
- de.addr = dsts[j].addr;
- de.amount = amount;
-
- new_dsts.push_back(de);
- }
-
- retVal.push_back(new_dsts);
- }
-
- return retVal;
-}
-} // anonymous namespace
-//----------------------------------------------------------------------------------------------------
crypto::hash wallet2::get_payment_id(const pending_tx &ptx) const
{
std::vector<tx_extra_field> tx_extra_fields;
@@ -5265,10 +5184,18 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size());
signed_txes.ptx.push_back(pending_tx());
tools::wallet2::pending_tx &ptx = signed_txes.ptx.back();
+ rct::RangeProofType range_proof_type = rct::RangeProofBorromean;
+ if (sd.use_bulletproofs)
+ {
+ range_proof_type = rct::RangeProofBulletproof;
+ for (const rct::Bulletproof &proof: ptx.tx.rct_signatures.p.bulletproofs)
+ if (proof.V.size() > 1)
+ range_proof_type = rct::RangeProofPaddedBulletproof;
+ }
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
rct::multisig_out msout;
- bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, sd.use_bulletproofs, m_multisig ? &msout : NULL);
+ bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, range_proof_type, m_multisig ? &msout : NULL);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
// we don't test tx size, because we don't know the current limit, due to not having a blockchain,
// and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway,
@@ -5681,7 +5608,15 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
cryptonote::transaction tx;
rct::multisig_out msout = ptx.multisig_sigs.front().msout;
auto sources = sd.sources;
- bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, sd.use_bulletproofs, &msout, false);
+ rct::RangeProofType range_proof_type = rct::RangeProofBorromean;
+ if (sd.use_bulletproofs)
+ {
+ range_proof_type = rct::RangeProofBulletproof;
+ for (const rct::Bulletproof &proof: ptx.tx.rct_signatures.p.bulletproofs)
+ if (proof.V.size() > 1)
+ range_proof_type = rct::RangeProofPaddedBulletproof;
+ }
+ bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, range_proof_type, &msout, false);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype);
THROW_WALLET_EXCEPTION_IF(get_transaction_prefix_hash (tx) != get_transaction_prefix_hash(ptx.tx),
@@ -5781,9 +5716,18 @@ bool wallet2::sign_multisig_tx_from_file(const std::string &filename, std::vecto
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::get_fee_multiplier(uint32_t priority, int fee_algorithm) const
{
- static const uint64_t old_multipliers[3] = {1, 2, 3};
- static const uint64_t new_multipliers[3] = {1, 20, 166};
- static const uint64_t newer_multipliers[4] = {1, 4, 20, 166};
+ static const struct
+ {
+ size_t count;
+ uint64_t multipliers[4];
+ }
+ multipliers[] =
+ {
+ { 3, {1, 2, 3} },
+ { 3, {1, 20, 166} },
+ { 4, {1, 4, 20, 166} },
+ { 4, {1, 5, 25, 1000} },
+ };
if (fee_algorithm == -1)
fee_algorithm = get_fee_algorithm();
@@ -5799,47 +5743,68 @@ uint64_t wallet2::get_fee_multiplier(uint32_t priority, int fee_algorithm) const
priority = 1;
}
+ THROW_WALLET_EXCEPTION_IF(fee_algorithm < 0 || fee_algorithm > 3, error::invalid_priority);
+
// 1 to 3/4 are allowed as priorities
- uint32_t max_priority = (fee_algorithm >= 2) ? 4 : 3;
+ const uint32_t max_priority = multipliers[fee_algorithm].count;
if (priority >= 1 && priority <= max_priority)
{
- switch (fee_algorithm)
- {
- case 0: return old_multipliers[priority-1];
- case 1: return new_multipliers[priority-1];
- case 2: return newer_multipliers[priority-1];
- default: THROW_WALLET_EXCEPTION_IF (true, error::invalid_priority);
- }
+ return multipliers[fee_algorithm].multipliers[priority-1];
}
THROW_WALLET_EXCEPTION_IF (false, error::invalid_priority);
return 1;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::get_dynamic_per_kb_fee_estimate() const
+uint64_t wallet2::get_dynamic_base_fee_estimate() const
{
uint64_t fee;
- boost::optional<std::string> result = m_node_rpc_proxy.get_dynamic_per_kb_fee_estimate(FEE_ESTIMATE_GRACE_BLOCKS, fee);
+ boost::optional<std::string> result = m_node_rpc_proxy.get_dynamic_base_fee_estimate(FEE_ESTIMATE_GRACE_BLOCKS, fee);
if (!result)
return fee;
- LOG_PRINT_L1("Failed to query per kB fee, using " << print_money(FEE_PER_KB));
- return FEE_PER_KB;
+ const uint64_t base_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE) ? FEE_PER_BYTE : FEE_PER_KB;
+ LOG_PRINT_L1("Failed to query base fee, using " << print_money(base_fee));
+ return base_fee;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::get_per_kb_fee() const
+uint64_t wallet2::get_base_fee() const
{
if(m_light_wallet)
- return m_light_wallet_per_kb_fee;
+ {
+ if (use_fork_rules(HF_VERSION_PER_BYTE_FEE))
+ return m_light_wallet_per_kb_fee / 1024;
+ else
+ return m_light_wallet_per_kb_fee;
+ }
bool use_dyn_fee = use_fork_rules(HF_VERSION_DYNAMIC_FEE, -720 * 1);
if (!use_dyn_fee)
return FEE_PER_KB;
- return get_dynamic_per_kb_fee_estimate();
+ return get_dynamic_base_fee_estimate();
+}
+//----------------------------------------------------------------------------------------------------
+uint64_t wallet2::get_fee_quantization_mask() const
+{
+ if(m_light_wallet)
+ {
+ return 1; // TODO
+ }
+ bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
+ if (!use_per_byte_fee)
+ return 1;
+
+ uint64_t fee_quantization_mask;
+ boost::optional<std::string> result = m_node_rpc_proxy.get_fee_quantization_mask(fee_quantization_mask);
+ if (result)
+ return 1;
+ return fee_quantization_mask;
}
//----------------------------------------------------------------------------------------------------
int wallet2::get_fee_algorithm() const
{
- // changes at v3 and v5
+ // changes at v3, v5, v8
+ if (use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0))
+ return 3;
if (use_fork_rules(5, 0))
return 2;
if (use_fork_rules(3, -720 * 14))
@@ -5847,19 +5812,39 @@ int wallet2::get_fee_algorithm() const
return 0;
}
//------------------------------------------------------------------------------------------------------------------------------
+uint64_t wallet2::get_min_ring_size() const
+{
+ if (use_fork_rules(8, 10))
+ return 11;
+ if (use_fork_rules(7, 10))
+ return 7;
+ if (use_fork_rules(6, 10))
+ return 5;
+ if (use_fork_rules(2, 10))
+ return 3;
+ return 0;
+}
+//------------------------------------------------------------------------------------------------------------------------------
+uint64_t wallet2::get_max_ring_size() const
+{
+ if (use_fork_rules(8, 10))
+ return 11;
+ return 0;
+}
+//------------------------------------------------------------------------------------------------------------------------------
uint64_t wallet2::adjust_mixin(uint64_t mixin) const
{
- if (mixin < 6 && use_fork_rules(7, 10)) {
- MWARNING("Requested ring size " << (mixin + 1) << " too low for hard fork 7, using 7");
- mixin = 6;
- }
- else if (mixin < 4 && use_fork_rules(6, 10)) {
- MWARNING("Requested ring size " << (mixin + 1) << " too low for hard fork 6, using 5");
- mixin = 4;
+ const uint64_t min_ring_size = get_min_ring_size();
+ if (mixin + 1 < min_ring_size)
+ {
+ MWARNING("Requested ring size " << (mixin + 1) << " too low, using " << min_ring_size);
+ mixin = min_ring_size-1;
}
- else if (mixin < 2 && use_fork_rules(2, 10)) {
- MWARNING("Requested ring size " << (mixin + 1) << " too low for hard fork 2, using 3");
- mixin = 2;
+ const uint64_t max_ring_size = get_max_ring_size();
+ if (max_ring_size && mixin + 1 > max_ring_size)
+ {
+ MWARNING("Requested ring size " << (mixin + 1) << " too high, using " << max_ring_size);
+ mixin = max_ring_size-1;
}
return mixin;
}
@@ -5871,7 +5856,10 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
try
{
// check if there's a backlog in the tx pool
- const double fee_level = get_fee_multiplier(1) * get_per_kb_fee() * (12/(double)13) / (double)1024;
+ const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
+ const uint64_t base_fee = get_base_fee();
+ const uint64_t fee_multiplier = get_fee_multiplier(1);
+ const double fee_level = fee_multiplier * base_fee * (use_per_byte_fee ? 1 : (12/(double)13 / (double)1024));
const std::vector<std::pair<uint64_t, uint64_t>> blocks = estimate_backlog({std::make_pair(fee_level, fee_level)});
if (blocks.size() != 1)
{
@@ -5885,10 +5873,10 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
}
// get the current full reward zone
- uint64_t block_size_limit = 0;
- const auto result = m_node_rpc_proxy.get_block_size_limit(block_size_limit);
+ uint64_t block_weight_limit = 0;
+ const auto result = m_node_rpc_proxy.get_block_weight_limit(block_weight_limit);
throw_on_rpc_response_error(result, "get_info");
- const uint64_t full_reward_zone = block_size_limit / 2;
+ const uint64_t full_reward_zone = block_weight_limit / 2;
// get the last N block headers and sum the block sizes
const size_t N = 10;
@@ -5912,14 +5900,14 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
MERROR("Bad blockheaders size");
return priority;
}
- size_t block_size_sum = 0;
+ size_t block_weight_sum = 0;
for (const cryptonote::block_header_response &i : getbh_res.headers)
{
- block_size_sum += i.block_size;
+ block_weight_sum += i.block_weight;
}
// estimate how 'full' the last N blocks are
- const size_t P = 100 * block_size_sum / (N * full_reward_zone);
+ const size_t P = 100 * block_weight_sum / (N * full_reward_zone);
MINFO((boost::format("The last %d blocks fill roughly %d%% of the full reward zone.") % N % P).str());
if (P > 80)
{
@@ -5937,115 +5925,6 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
return priority;
}
//----------------------------------------------------------------------------------------------------
-// separated the call(s) to wallet2::transfer into their own function
-//
-// this function will make multiple calls to wallet2::transfer if multiple
-// transactions will be required
-std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon)
-{
- const std::vector<size_t> unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, true, trusted_daemon);
-
- const uint64_t fee_per_kb = get_per_kb_fee();
- const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
-
- // failsafe split attempt counter
- size_t attempt_count = 0;
-
- for(attempt_count = 1; ;attempt_count++)
- {
- size_t num_tx = 0.5 + pow(1.7,attempt_count-1);
-
- auto split_values = split_amounts(dsts, num_tx);
-
- // Throw if split_amounts comes back with a vector of size different than it should
- if (split_values.size() != num_tx)
- {
- throw std::runtime_error("Splitting transactions returned a number of potential tx not equal to what was requested");
- }
-
- std::vector<pending_tx> ptx_vector;
- try
- {
- // for each new destination vector (i.e. for each new tx)
- for (auto & dst_vector : split_values)
- {
- cryptonote::transaction tx;
- pending_tx ptx;
-
- // loop until fee is met without increasing tx size to next KB boundary.
- const size_t estimated_tx_size = estimate_tx_size(false, unused_transfers_indices.size(), fake_outs_count, dst_vector.size(), extra.size(), false);
- uint64_t needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
- do
- {
- transfer(dst_vector, fake_outs_count, unused_transfers_indices, unlock_time, needed_fee, extra, tx, ptx, trusted_daemon);
- auto txBlob = t_serializable_object_to_blob(ptx.tx);
- needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
- } while (ptx.fee < needed_fee);
-
- ptx_vector.push_back(ptx);
-
- // mark transfers to be used as "spent"
- for(size_t idx: ptx.selected_transfers)
- {
- set_spent(idx, 0);
- }
- }
-
- // if we made it this far, we've selected our transactions. committing them will mark them spent,
- // so this is a failsafe in case they don't go through
- // unmark pending tx transfers as spent
- for (auto & ptx : ptx_vector)
- {
- // mark transfers to be used as not spent
- for(size_t idx2: ptx.selected_transfers)
- {
- set_unspent(idx2);
- }
-
- }
-
- // if we made it this far, we're OK to actually send the transactions
- return ptx_vector;
-
- }
- // only catch this here, other exceptions need to pass through to the calling function
- catch (const tools::error::tx_too_big& e)
- {
-
- // unmark pending tx transfers as spent
- for (auto & ptx : ptx_vector)
- {
- // mark transfers to be used as not spent
- for(size_t idx2: ptx.selected_transfers)
- {
- set_unspent(idx2);
- }
- }
-
- if (attempt_count >= MAX_SPLIT_ATTEMPTS)
- {
- throw;
- }
- }
- catch (...)
- {
- // in case of some other exception, make sure any tx in queue are marked unspent again
-
- // unmark pending tx transfers as spent
- for (auto & ptx : ptx_vector)
- {
- // mark transfers to be used as not spent
- for(size_t idx2: ptx.selected_transfers)
- {
- set_unspent(idx2);
- }
- }
-
- throw;
- }
- }
-}
-
bool wallet2::set_ring_database(const std::string &filename)
{
m_ring_database = filename;
@@ -6218,7 +6097,7 @@ bool wallet2::find_and_save_rings(bool force)
return true;
}
-bool wallet2::blackball_output(const crypto::public_key &output)
+bool wallet2::blackball_output(const std::pair<uint64_t, uint64_t> &output)
{
if (!m_ringdb)
return false;
@@ -6226,7 +6105,7 @@ bool wallet2::blackball_output(const crypto::public_key &output)
catch (const std::exception &e) { return false; }
}
-bool wallet2::set_blackballed_outputs(const std::vector<crypto::public_key> &outputs, bool add)
+bool wallet2::set_blackballed_outputs(const std::vector<std::pair<uint64_t, uint64_t>> &outputs, bool add)
{
if (!m_ringdb)
return false;
@@ -6235,14 +6114,13 @@ bool wallet2::set_blackballed_outputs(const std::vector<crypto::public_key> &out
bool ret = true;
if (!add)
ret &= m_ringdb->clear_blackballs();
- for (const auto &output: outputs)
- ret &= m_ringdb->blackball(output);
+ ret &= m_ringdb->blackball(outputs);
return ret;
}
catch (const std::exception &e) { return false; }
}
-bool wallet2::unblackball_output(const crypto::public_key &output)
+bool wallet2::unblackball_output(const std::pair<uint64_t, uint64_t> &output)
{
if (!m_ringdb)
return false;
@@ -6250,7 +6128,7 @@ bool wallet2::unblackball_output(const crypto::public_key &output)
catch (const std::exception &e) { return false; }
}
-bool wallet2::is_output_blackballed(const crypto::public_key &output) const
+bool wallet2::is_output_blackballed(const std::pair<uint64_t, uint64_t> &output) const
{
if (!m_ringdb)
return false;
@@ -6295,8 +6173,8 @@ bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_out
CHECK_AND_ASSERT_MES(!outs.empty(), false, "internal error: outs is empty");
if (std::find(outs.back().begin(), outs.back().end(), item) != outs.back().end()) // don't add duplicates
return false;
- if (is_output_blackballed(output_public_key)) // don't add blackballed outputs
- return false;
+// if (is_output_blackballed(output_public_key)) // don't add blackballed outputs
+// return false;
outs.back().push_back(item);
return true;
}
@@ -6476,6 +6354,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
req_t.from_height = std::max<uint64_t>(segregation_fork_height, RECENT_OUTPUT_BLOCKS) - RECENT_OUTPUT_BLOCKS;
req_t.to_height = segregation_fork_height + 1;
req_t.cumulative = true;
+ req_t.binary = true;
m_daemon_rpc_mutex.lock();
bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_distribution", req_t, resp_t, m_http_client, rpc_timeout * 1000);
m_daemon_rpc_mutex.unlock();
@@ -6792,6 +6671,8 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (seen_indices.count(i))
continue;
+ if (is_output_blackballed(std::make_pair(amount, i))) // don't add blackballed outputs
+ continue;
seen_indices.emplace(i);
LOG_PRINT_L2("picking " << i << " as " << type);
@@ -6814,7 +6695,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin");
THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_random_outs_error, daemon_resp.status);
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_outs_error, daemon_resp.status);
THROW_WALLET_EXCEPTION_IF(daemon_resp.outs.size() != req.outputs.size(), error::wallet_internal_error,
"daemon returned wrong response for get_outs.bin, wrong amounts count = " +
std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(req.outputs.size()));
@@ -6948,7 +6829,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
THROW_WALLET_EXCEPTION_IF(m_multisig, error::wallet_internal_error, "Multisig wallets cannot spend non rct outputs");
- uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
+ uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit();
uint64_t needed_money = fee;
LOG_PRINT_L2("transfer: starting with fee " << print_money (needed_money));
@@ -7050,10 +6931,10 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
std::vector<crypto::secret_key> additional_tx_keys;
rct::multisig_out msout;
LOG_PRINT_L2("constructing tx");
- bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, false, m_multisig ? &msout : NULL);
+ bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, rct::RangeProofBulletproof, m_multisig ? &msout : NULL);
LOG_PRINT_L2("constructed tx, r="<<r);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype);
- THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
+ THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit);
std::string key_images;
bool all_are_txin_to_key = std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
@@ -7099,13 +6980,13 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
void wallet2::transfer_selected_rct(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,
- uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, bool bulletproof)
+ uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, rct::RangeProofType range_proof_type)
{
using namespace cryptonote;
// throw if attempting a transaction with no destinations
THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
- uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
+ uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit();
uint64_t needed_money = fee;
LOG_PRINT_L2("transfer_selected_rct: starting with fee " << print_money (needed_money));
LOG_PRINT_L2("selected transfers: " << strjoin(selected_transfers, " "));
@@ -7255,10 +7136,10 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
rct::multisig_out msout;
LOG_PRINT_L2("constructing tx");
auto sources_copy = sources;
- bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, bulletproof, m_multisig ? &msout : NULL);
+ bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, range_proof_type, m_multisig ? &msout : NULL);
LOG_PRINT_L2("constructed tx, r="<<r);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_nettype);
- THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
+ THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit);
// work out the permutation done on sources
std::vector<size_t> ins_order;
@@ -7300,10 +7181,10 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
LOG_PRINT_L2("Creating supplementary multisig transaction");
cryptonote::transaction ms_tx;
auto sources_copy_copy = sources_copy;
- bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources_copy_copy, splitted_dsts, change_dts.addr, extra, ms_tx, unlock_time,tx_key, additional_tx_keys, true, bulletproof, &msout, false);
+ bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources_copy_copy, splitted_dsts, change_dts.addr, extra, ms_tx, unlock_time,tx_key, additional_tx_keys, true, range_proof_type, &msout, false);
LOG_PRINT_L2("constructed tx, r="<<r);
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype);
- THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
+ THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit);
THROW_WALLET_EXCEPTION_IF(cryptonote::get_transaction_prefix_hash(ms_tx) != prefix_hash, error::wallet_internal_error, "Multisig txes do not share prefix");
multisig_sigs.push_back({ms_tx.rct_signatures, multisig_signers[signer_index], new_used_L, std::unordered_set<crypto::public_key>(), msout});
@@ -7951,7 +7832,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image,
// This system allows for sending (almost) the entire balance, since it does
// not generate spurious change in all txes, thus decreasing the instantaneous
// usable balance.
-std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, bool trusted_daemon)
+std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
//ensure device is let in NONE mode in any case
hw::device &hwdev = m_account.get_device();
@@ -7971,11 +7852,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
std::vector<cryptonote::tx_destination_entry> dsts;
cryptonote::transaction tx;
pending_tx ptx;
- size_t bytes;
+ size_t weight;
uint64_t needed_fee;
std::vector<std::vector<tools::wallet2::get_outs_entry>> outs;
- TX() : bytes(0), needed_fee(0) {}
+ TX() : weight(0), needed_fee(0) {}
void add(const account_public_address &addr, bool is_subaddress, uint64_t amount, unsigned int original_output_index, bool merge_destinations) {
if (merge_destinations)
@@ -8003,12 +7884,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
std::vector<TX> txes;
bool adding_fee; // true if new outputs go towards fee, rather than destinations
uint64_t needed_fee, available_for_fee = 0;
- uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
+ uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit();
+ const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
const bool use_rct = use_fork_rules(4, 0);
const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
+ const rct::RangeProofType range_proof_type = bulletproof ? rct::RangeProofPaddedBulletproof : rct::RangeProofBorromean;
- const uint64_t fee_per_kb = get_per_kb_fee();
+ const uint64_t base_fee = get_base_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
+ const uint64_t fee_quantization_mask = get_fee_quantization_mask();
// throw if attempting a transaction with no destinations
THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
@@ -8039,7 +7923,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// early out if we know we can't make it anyway
// we could also check for being within FEE_PER_KB, but if the fee calculation
// ever changes, this might be missed, so let this go through
- const uint64_t min_fee = (fee_multiplier * fee_per_kb * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof)) / 1024;
+ const uint64_t min_fee = (fee_multiplier * base_fee * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof)) / 1024;
uint64_t balance_subtotal = 0;
uint64_t unlocked_balance_subtotal = 0;
for (uint32_t index_minor : subaddr_indices)
@@ -8057,11 +7941,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Candidate subaddress index for spending: " << i);
// determine threshold for fractional amount
- const size_t tx_size_one_ring = estimate_tx_size(use_rct, 1, fake_outs_count, 2, 0, bulletproof);
- const size_t tx_size_two_rings = estimate_tx_size(use_rct, 2, fake_outs_count, 2, 0, bulletproof);
- THROW_WALLET_EXCEPTION_IF(tx_size_one_ring > tx_size_two_rings, error::wallet_internal_error, "Estimated tx size with 1 input is larger than with 2 inputs!");
- const size_t tx_size_per_ring = tx_size_two_rings - tx_size_one_ring;
- const uint64_t fractional_threshold = (fee_multiplier * fee_per_kb * tx_size_per_ring) / 1024;
+ const size_t tx_weight_one_ring = estimate_tx_weight(use_rct, 1, fake_outs_count, 2, 0, bulletproof);
+ const size_t tx_weight_two_rings = estimate_tx_weight(use_rct, 2, fake_outs_count, 2, 0, bulletproof);
+ THROW_WALLET_EXCEPTION_IF(tx_weight_one_ring > tx_weight_two_rings, error::wallet_internal_error, "Estimated tx weight with 1 input is larger than with 2 inputs!");
+ const size_t tx_weight_per_ring = tx_weight_two_rings - tx_weight_one_ring;
+ const uint64_t fractional_threshold = (fee_multiplier * base_fee * tx_weight_per_ring) / (use_per_byte_fee ? 1 : 1024);
// gather all dust and non-dust outputs belonging to specified subaddresses
size_t num_nondust_outputs = 0;
@@ -8154,7 +8038,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
{
// this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which
// will get us a known fee.
- uint64_t estimated_fee = calculate_fee(fee_per_kb, estimate_rct_tx_size(2, fake_outs_count, 2, extra.size(), bulletproof), fee_multiplier);
+ uint64_t estimated_fee = estimate_fee(use_per_byte_fee, use_rct, 2, fake_outs_count, 2, extra.size(), bulletproof, base_fee, fee_multiplier, fee_quantization_mask);
preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices);
if (!preferred_inputs.empty())
{
@@ -8196,7 +8080,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) {
TX &tx = txes.back();
- LOG_PRINT_L2("Start of loop with " << unused_transfers_indices->size() << " " << unused_dust_indices->size());
+ LOG_PRINT_L2("Start of loop with " << unused_transfers_indices->size() << " " << unused_dust_indices->size() << ", tx.dsts.size() " << tx.dsts.size());
LOG_PRINT_L2("unused_transfers_indices: " << strjoin(*unused_transfers_indices, " "));
LOG_PRINT_L2("unused_dust_indices: " << strjoin(*unused_dust_indices, " "));
LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? "-" : cryptonote::print_money(dsts[0].amount)));
@@ -8259,7 +8143,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
else
{
- while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit))
+ while (!dsts.empty() && dsts[0].amount <= available_amount && estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof) < TX_WEIGHT_TARGET(upper_transaction_weight_limit))
{
// we can fully pay that destination
LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) <<
@@ -8271,7 +8155,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
++original_output_index;
}
- if (available_amount > 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit)) {
+ if (available_amount > 0 && !dsts.empty() && estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof) < TX_WEIGHT_TARGET(upper_transaction_weight_limit)) {
// we can partially fill that destination
LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) <<
" for " << print_money(available_amount) << "/" << print_money(dsts[0].amount));
@@ -8283,7 +8167,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// here, check if we need to sent tx and start a new one
LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
- << upper_transaction_size_limit);
+ << upper_transaction_weight_limit);
bool try_tx = false;
// if we have preferred picks, but haven't yet used all of them, continue
if (preferred_inputs.empty())
@@ -8295,8 +8179,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
else
{
- const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
- try_tx = dsts.empty() || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
+ const size_t estimated_rct_tx_weight = estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof);
+ try_tx = dsts.empty() || (estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit));
}
}
@@ -8304,8 +8188,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
cryptonote::transaction test_tx;
pending_tx test_ptx;
- const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
- needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
+ needed_fee = estimate_fee(use_per_byte_fee, use_rct ,tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, base_fee, fee_multiplier, fee_multiplier);
uint64_t inputs = 0, outputs = needed_fee;
for (size_t idx: tx.selected_transfers) inputs += m_transfers[idx].amount();
@@ -8322,14 +8205,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
tx.selected_transfers.size() << " inputs");
if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
- test_tx, test_ptx, bulletproof);
+ test_tx, test_ptx, range_proof_type);
else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
- needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
+ needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0);
- LOG_PRINT_L2("Made a " << get_size_string(txBlob) << " tx, with " << print_money(available_for_fee) << " available for fee (" <<
+ LOG_PRINT_L2("Made a " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(available_for_fee) << " available for fee (" <<
print_money(needed_fee) << " needed)");
if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0)
@@ -8365,22 +8248,22 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
while (needed_fee > test_ptx.fee) {
if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
- test_tx, test_ptx, bulletproof);
+ test_tx, test_ptx, range_proof_type);
else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
txBlob = t_serializable_object_to_blob(test_ptx.tx);
- needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
- LOG_PRINT_L2("Made an attempt at a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) <<
+ needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
+ LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) <<
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
}
- LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) <<
+ LOG_PRINT_L2("Made a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) <<
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
tx.tx = test_tx;
tx.ptx = test_ptx;
- tx.bytes = txBlob.size();
+ tx.weight = get_transaction_weight(test_tx, txBlob.size());
tx.outs = outs;
tx.needed_fee = needed_fee;
accumulated_fee += test_ptx.fee;
@@ -8438,7 +8321,7 @@ skip_tx:
extra, /* const std::vector<uint8_t>& extra, */
test_tx, /* OUT cryptonote::transaction& tx, */
test_ptx, /* OUT cryptonote::transaction& tx, */
- bulletproof);
+ range_proof_type);
} else {
transfer_selected(tx.dsts,
tx.selected_transfers,
@@ -8455,7 +8338,7 @@ skip_tx:
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
tx.tx = test_tx;
tx.ptx = test_ptx;
- tx.bytes = txBlob.size();
+ tx.weight = get_transaction_weight(test_tx, txBlob.size());
}
std::vector<wallet2::pending_tx> ptx_vector;
@@ -8466,7 +8349,7 @@ skip_tx:
for (size_t idx: tx.selected_transfers)
tx_money += m_transfers[idx].amount();
LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
- " " << get_transaction_hash(tx.ptx.tx) << ": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() <<
+ " " << get_transaction_hash(tx.ptx.tx) << ": " << get_weight_string(tx.weight) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() <<
" outputs to " << tx.dsts.size() << " destination(s), including " <<
print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change");
ptx_vector.push_back(tx.ptx);
@@ -8476,7 +8359,7 @@ skip_tx:
return ptx_vector;
}
-std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, bool trusted_daemon)
+std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices;
@@ -8527,10 +8410,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
}
}
- return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, trusted_daemon);
+ return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
}
-std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon)
+std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
{
std::vector<size_t> unused_transfers_indices;
std::vector<size_t> unused_dust_indices;
@@ -8548,10 +8431,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
break;
}
}
- return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, trusted_daemon);
+ return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
}
-std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon)
+std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
{
//ensure device is let in NONE mode in any case
hw::device &hwdev = m_account.get_device();
@@ -8564,21 +8447,24 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
std::vector<cryptonote::tx_destination_entry> dsts;
cryptonote::transaction tx;
pending_tx ptx;
- size_t bytes;
+ size_t weight;
uint64_t needed_fee;
std::vector<std::vector<get_outs_entry>> outs;
- TX() : bytes(0), needed_fee(0) {}
+ TX() : weight(0), needed_fee(0) {}
};
std::vector<TX> txes;
uint64_t needed_fee, available_for_fee = 0;
- uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
+ uint64_t upper_transaction_weight_limit = get_upper_transaction_weight_limit();
std::vector<std::vector<get_outs_entry>> outs;
+ const bool use_per_byte_fee = use_fork_rules(HF_VERSION_PER_BYTE_FEE);
const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0);
const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0);
- const uint64_t fee_per_kb = get_per_kb_fee();
+ const rct::RangeProofType range_proof_type = bulletproof ? rct::RangeProofPaddedBulletproof : rct::RangeProofBorromean;
+ const uint64_t base_fee = get_base_fee();
const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm());
+ const uint64_t fee_quantization_mask = get_fee_quantization_mask();
LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs");
@@ -8600,7 +8486,25 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
// get a random unspent output and use it to pay next chunk. We try to alternate
// dust and non dust to ensure we never get with only dust, from which we might
// get a tx that can't pay for itself
- size_t idx = unused_transfers_indices.empty() ? pop_best_value(unused_dust_indices, tx.selected_transfers) : unused_dust_indices.empty() ? pop_best_value(unused_transfers_indices, tx.selected_transfers) : ((tx.selected_transfers.size() & 1) || accumulated_outputs > fee_per_kb * fee_multiplier * (upper_transaction_size_limit + 1023) / 1024) ? pop_best_value(unused_dust_indices, tx.selected_transfers) : pop_best_value(unused_transfers_indices, tx.selected_transfers);
+ uint64_t fee_dust_threshold;
+ if (use_fork_rules(HF_VERSION_PER_BYTE_FEE))
+ {
+ const uint64_t estimated_tx_weight_with_one_extra_output = estimate_tx_weight(use_rct, tx.selected_transfers.size() + 1, fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof);
+ fee_dust_threshold = calculate_fee_from_weight(base_fee, estimated_tx_weight_with_one_extra_output, fee_multiplier, fee_quantization_mask);
+ }
+ else
+ {
+ fee_dust_threshold = base_fee * fee_multiplier * (upper_transaction_weight_limit + 1023) / 1024;
+ }
+
+ size_t idx =
+ unused_transfers_indices.empty()
+ ? pop_best_value(unused_dust_indices, tx.selected_transfers)
+ : unused_dust_indices.empty()
+ ? pop_best_value(unused_transfers_indices, tx.selected_transfers)
+ : ((tx.selected_transfers.size() & 1) || accumulated_outputs > fee_dust_threshold)
+ ? pop_best_value(unused_dust_indices, tx.selected_transfers)
+ : pop_best_value(unused_transfers_indices, tx.selected_transfers);
const transfer_details &td = m_transfers[idx];
LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount()));
@@ -8615,16 +8519,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
// here, check if we need to sent tx and start a new one
LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit "
- << upper_transaction_size_limit);
- const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size(), bulletproof);
- bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit));
+ << upper_transaction_weight_limit);
+ const size_t estimated_rct_tx_weight = estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 2, extra.size(), bulletproof);
+ bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_weight >= TX_WEIGHT_TARGET(upper_transaction_weight_limit));
if (try_tx) {
cryptonote::transaction test_tx;
pending_tx test_ptx;
- const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
- needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
+ needed_fee = estimate_fee(use_per_byte_fee, use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, base_fee, fee_multiplier, fee_quantization_mask);
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
@@ -8632,14 +8535,14 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
tx.selected_transfers.size() << " outputs");
if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
- test_tx, test_ptx, bulletproof);
+ test_tx, test_ptx, range_proof_type);
else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
- needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
+ needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
available_for_fee = test_ptx.fee + test_ptx.dests[0].amount + test_ptx.change_dts.amount;
- LOG_PRINT_L2("Made a " << get_size_string(txBlob) << " tx, with " << print_money(available_for_fee) << " available for fee (" <<
+ LOG_PRINT_L2("Made a " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(available_for_fee) << " available for fee (" <<
print_money(needed_fee) << " needed)");
THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, "Transaction cannot pay for itself");
@@ -8649,22 +8552,22 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
tx.dsts[0].amount = available_for_fee - needed_fee;
if (use_rct)
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
- test_tx, test_ptx, bulletproof);
+ test_tx, test_ptx, range_proof_type);
else
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
txBlob = t_serializable_object_to_blob(test_ptx.tx);
- needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier);
- LOG_PRINT_L2("Made an attempt at a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) <<
+ needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
+ LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) <<
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
} while (needed_fee > test_ptx.fee);
- LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) <<
+ LOG_PRINT_L2("Made a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) <<
" fee and " << print_money(test_ptx.change_dts.amount) << " change");
tx.tx = test_tx;
tx.ptx = test_ptx;
- tx.bytes = txBlob.size();
+ tx.weight = get_transaction_weight(test_tx, txBlob.size());
tx.outs = outs;
tx.needed_fee = needed_fee;
accumulated_fee += test_ptx.fee;
@@ -8688,7 +8591,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
pending_tx test_ptx;
if (use_rct) {
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.needed_fee, extra,
- test_tx, test_ptx, bulletproof);
+ test_tx, test_ptx, range_proof_type);
} else {
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
@@ -8696,7 +8599,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
tx.tx = test_tx;
tx.ptx = test_ptx;
- tx.bytes = txBlob.size();
+ tx.weight = get_transaction_weight(test_tx, txBlob.size());
}
std::vector<wallet2::pending_tx> ptx_vector;
@@ -8707,7 +8610,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
for (size_t idx: tx.selected_transfers)
tx_money += m_transfers[idx].amount();
LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() <<
- " " << get_transaction_hash(tx.ptx.tx) << ": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() <<
+ " " << get_transaction_hash(tx.ptx.tx) << ": " << get_weight_string(tx.weight) << ", sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() <<
" outputs to " << tx.dsts.size() << " destination(s), including " <<
print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change");
ptx_vector.push_back(tx.ptx);
@@ -8742,12 +8645,15 @@ bool wallet2::use_fork_rules(uint8_t version, int64_t early_blocks) const
return close_enough;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::get_upper_transaction_size_limit() const
+uint64_t wallet2::get_upper_transaction_weight_limit() const
{
- if (m_upper_transaction_size_limit > 0)
- return m_upper_transaction_size_limit;
+ if (m_upper_transaction_weight_limit > 0)
+ return m_upper_transaction_weight_limit;
uint64_t full_reward_zone = use_fork_rules(5, 10) ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5 : use_fork_rules(2, 10) ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 : CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1;
- return full_reward_zone - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
+ if (use_fork_rules(8, 10))
+ return full_reward_zone / 2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
+ else
+ return full_reward_zone - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
}
//----------------------------------------------------------------------------------------------------
std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(const transfer_details &td)> &f) const
@@ -8785,12 +8691,12 @@ std::vector<uint64_t> wallet2::get_unspent_amounts_vector() const
return vector;
}
//----------------------------------------------------------------------------------------------------
-std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct, bool trusted_daemon)
+std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct)
{
cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t);
m_daemon_rpc_mutex.lock();
- if (trusted_daemon)
+ if (is_trusted_daemon())
req_t.amounts = get_unspent_amounts_vector();
req_t.min_count = count;
req_t.max_count = 0;
@@ -8851,30 +8757,28 @@ const wallet2::transfer_details &wallet2::get_transfer_details(size_t idx) const
return m_transfers[idx];
}
//----------------------------------------------------------------------------------------------------
-std::vector<size_t> wallet2::select_available_unmixable_outputs(bool trusted_daemon)
+std::vector<size_t> wallet2::select_available_unmixable_outputs()
{
- // request all outputs with less than 3 instances
- const size_t min_mixin = use_fork_rules(7, 10) ? 6 : use_fork_rules(6, 10) ? 4 : 2; // v6 increases min mixin from 2 to 4, v7 to 6
- return select_available_outputs_from_histogram(min_mixin + 1, false, true, false, trusted_daemon);
+ // request all outputs with less instances than the min ring size
+ return select_available_outputs_from_histogram(get_min_ring_size(), false, true, false);
}
//----------------------------------------------------------------------------------------------------
-std::vector<size_t> wallet2::select_available_mixable_outputs(bool trusted_daemon)
+std::vector<size_t> wallet2::select_available_mixable_outputs()
{
- // request all outputs with at least 3 instances, so we can use mixin 2 with
- const size_t min_mixin = use_fork_rules(7, 10) ? 6 : use_fork_rules(6, 10) ? 4 : 2; // v6 increases min mixin from 2 to 4, v7 to 6
- return select_available_outputs_from_histogram(min_mixin + 1, true, true, true, trusted_daemon);
+ // request all outputs with at least as many instances as the min ring size
+ return select_available_outputs_from_histogram(get_min_ring_size(), true, true, true);
}
//----------------------------------------------------------------------------------------------------
-std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bool trusted_daemon)
+std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions()
{
// From hard fork 1, we don't consider small amounts to be dust anymore
const bool hf1_rules = use_fork_rules(2, 10); // first hard fork has version 2
tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD);
- const uint64_t fee_per_kb = get_per_kb_fee();
+ const uint64_t base_fee = get_base_fee();
// may throw
- std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs(trusted_daemon);
+ std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
size_t num_dust_outputs = unmixable_outputs.size();
if (num_dust_outputs == 0)
@@ -8886,19 +8790,19 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo
std::vector<size_t> unmixable_transfer_outputs, unmixable_dust_outputs;
for (auto n: unmixable_outputs)
{
- if (m_transfers[n].amount() < fee_per_kb)
+ if (m_transfers[n].amount() < base_fee)
unmixable_dust_outputs.push_back(n);
else
unmixable_transfer_outputs.push_back(n);
}
- return create_transactions_from(m_account_public_address, false, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>(), trusted_daemon);
+ return create_transactions_from(m_account_public_address, false, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>());
}
//----------------------------------------------------------------------------------------------------
-void wallet2::discard_unmixable_outputs(bool trusted_daemon)
+void wallet2::discard_unmixable_outputs()
{
// may throw
- std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs(trusted_daemon);
+ std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
for (size_t idx : unmixable_outputs)
{
m_transfers[idx].m_spent = true;
@@ -9279,6 +9183,8 @@ void wallet2::check_tx_key_helper(const crypto::hash &txid, const crypto::key_de
hwdev.ecdhDecode(ecdh_info, rct::sk2rct(scalar1));
const rct::key C = tx.rct_signatures.outPk[n].mask;
rct::key Ctmp;
+ THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.mask.bytes) != 0, error::wallet_internal_error, "Bad ECDH input mask");
+ THROW_WALLET_EXCEPTION_IF(sc_check(ecdh_info.amount.bytes) != 0, error::wallet_internal_error, "Bad ECDH input amount");
rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H);
if (rct::equalKeys(C, Ctmp))
amount = rct::h2d(ecdh_info.amount);
@@ -9566,6 +9472,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
if (account_minreserve)
{
+ THROW_WALLET_EXCEPTION_IF(account_minreserve->second == 0, error::wallet_internal_error, "Proved amount must be greater than 0");
// minimize the number of outputs included in the proof, by only picking the N largest outputs that can cover the requested min reserve amount
std::sort(selected_transfers.begin(), selected_transfers.end(), [&](const size_t a, const size_t b)
{ return m_transfers[a].amount() > m_transfers[b].amount(); });
@@ -9849,7 +9756,7 @@ uint64_t wallet2::get_approximate_blockchain_height() const
// Calculated blockchain height
uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
// testnet got some huge rollbacks, so the estimation is way off
- static const uint64_t approximate_testnet_rolled_back_blocks = 148540;
+ static const uint64_t approximate_testnet_rolled_back_blocks = 303967;
if (m_nettype == TESTNET && approx_blockchain_height > approximate_testnet_rolled_back_blocks)
approx_blockchain_height -= approximate_testnet_rolled_back_blocks;
LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
@@ -11207,46 +11114,46 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std::
THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_txpool_backlog");
THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
- uint64_t block_size_limit = 0;
- const auto result = m_node_rpc_proxy.get_block_size_limit(block_size_limit);
+ uint64_t block_weight_limit = 0;
+ const auto result = m_node_rpc_proxy.get_block_weight_limit(block_weight_limit);
throw_on_rpc_response_error(result, "get_info");
- uint64_t full_reward_zone = block_size_limit / 2;
- THROW_WALLET_EXCEPTION_IF(full_reward_zone == 0, error::wallet_internal_error, "Invalid block size limit from daemon");
+ uint64_t full_reward_zone = block_weight_limit / 2;
+ THROW_WALLET_EXCEPTION_IF(full_reward_zone == 0, error::wallet_internal_error, "Invalid block weight limit from daemon");
std::vector<std::pair<uint64_t, uint64_t>> blocks;
for (const auto &fee_level: fee_levels)
{
const double our_fee_byte_min = fee_level.first;
const double our_fee_byte_max = fee_level.second;
- uint64_t priority_size_min = 0, priority_size_max = 0;
+ uint64_t priority_weight_min = 0, priority_weight_max = 0;
for (const auto &i: res.backlog)
{
- if (i.blob_size == 0)
+ if (i.weight == 0)
{
- MWARNING("Got 0 sized blob from txpool, ignored");
+ MWARNING("Got 0 weight tx from txpool, ignored");
continue;
}
- double this_fee_byte = i.fee / (double)i.blob_size;
+ double this_fee_byte = i.fee / (double)i.weight;
if (this_fee_byte >= our_fee_byte_min)
- priority_size_min += i.blob_size;
+ priority_weight_min += i.weight;
if (this_fee_byte >= our_fee_byte_max)
- priority_size_max += i.blob_size;
+ priority_weight_max += i.weight;
}
- uint64_t nblocks_min = priority_size_min / full_reward_zone;
- uint64_t nblocks_max = priority_size_max / full_reward_zone;
- MDEBUG("estimate_backlog: priority_size " << priority_size_min << " - " << priority_size_max << " for "
+ uint64_t nblocks_min = priority_weight_min / full_reward_zone;
+ uint64_t nblocks_max = priority_weight_max / full_reward_zone;
+ MDEBUG("estimate_backlog: priority_weight " << priority_weight_min << " - " << priority_weight_max << " for "
<< our_fee_byte_min << " - " << our_fee_byte_max << " piconero byte fee, "
- << nblocks_min << " - " << nblocks_max << " blocks at block size " << full_reward_zone);
+ << nblocks_min << " - " << nblocks_max << " blocks at block weight " << full_reward_zone);
blocks.push_back(std::make_pair(nblocks_min, nblocks_max));
}
return blocks;
}
//----------------------------------------------------------------------------------------------------
-std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(uint64_t min_blob_size, uint64_t max_blob_size, const std::vector<uint64_t> &fees)
+std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(uint64_t min_tx_weight, uint64_t max_tx_weight, const std::vector<uint64_t> &fees)
{
- THROW_WALLET_EXCEPTION_IF(min_blob_size == 0, error::wallet_internal_error, "Invalid 0 fee");
- THROW_WALLET_EXCEPTION_IF(max_blob_size == 0, error::wallet_internal_error, "Invalid 0 fee");
+ THROW_WALLET_EXCEPTION_IF(min_tx_weight == 0, error::wallet_internal_error, "Invalid 0 fee");
+ THROW_WALLET_EXCEPTION_IF(max_tx_weight == 0, error::wallet_internal_error, "Invalid 0 fee");
for (uint64_t fee: fees)
{
THROW_WALLET_EXCEPTION_IF(fee == 0, error::wallet_internal_error, "Invalid 0 fee");
@@ -11254,7 +11161,7 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(uint64_t mi
std::vector<std::pair<double, double>> fee_levels;
for (uint64_t fee: fees)
{
- double our_fee_byte_min = fee / (double)min_blob_size, our_fee_byte_max = fee / (double)max_blob_size;
+ double our_fee_byte_min = fee / (double)min_tx_weight, our_fee_byte_max = fee / (double)max_tx_weight;
fee_levels.emplace_back(our_fee_byte_min, our_fee_byte_max);
}
return estimate_backlog(fee_levels);
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 2d45f4e3e..02982296e 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -544,8 +544,9 @@ namespace tools
* \param wallet_ Name of wallet file
* \param password Password of wallet file
* \param device_name name of HW to use
+ * \param create_address_file Whether to create an address file
*/
- void restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name);
+ void restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name, bool create_address_file);
/*!
* \brief Creates a multisig wallet
@@ -630,20 +631,18 @@ namespace tools
void explicit_refresh_from_block_height(bool expl) {m_explicit_refresh_from_block_height = expl;}
bool explicit_refresh_from_block_height() const {return m_explicit_refresh_from_block_height;}
- // upper_transaction_size_limit as defined below is set to
- // approximately 125% of the fixed minimum allowable penalty
- // free block size. TODO: fix this so that it actually takes
- // into account the current median block size rather than
- // the minimum block size.
bool deinit();
bool init(bool rpc, std::string daemon_address = "http://localhost:8080",
- boost::optional<epee::net_utils::http::login> daemon_login = boost::none, uint64_t upper_transaction_size_limit = 0, bool ssl = false);
+ boost::optional<epee::net_utils::http::login> daemon_login = boost::none, uint64_t upper_transaction_weight_limit = 0, bool ssl = false, bool trusted_daemon = false);
void stop() { m_run.store(false, std::memory_order_relaxed); }
i_wallet2_callback* callback() const { return m_callback; }
void callback(i_wallet2_callback* callback) { m_callback = callback; }
+ bool is_trusted_daemon() const { return m_trusted_daemon; }
+ void set_trusted_daemon(bool trusted) { m_trusted_daemon = trusted; }
+
/*!
* \brief Checks if deterministic wallet
*/
@@ -715,18 +714,12 @@ namespace tools
uint64_t balance_all() const;
uint64_t unlocked_balance_all() const;
template<typename T>
- void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, bool trusted_daemon);
- template<typename T>
- void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon);
- void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, bool trusted_daemon);
- void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon);
- 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,
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx);
void transfer_selected_rct(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,
- uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, bool bulletproof);
+ uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, rct::RangeProofType range_proof_type);
void commit_tx(pending_tx& ptx_vector);
void commit_tx(std::vector<pending_tx>& ptx_vector);
@@ -748,18 +741,17 @@ namespace tools
bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const;
bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func);
- std::vector<pending_tx> create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon);
- std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, bool trusted_daemon); // pass subaddr_indices by value on purpose
- std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, bool trusted_daemon);
- std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon);
- std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, bool trusted_daemon);
+ std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices); // pass subaddr_indices by value on purpose
+ std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices);
+ std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
+ std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
bool load_multisig_tx(cryptonote::blobdata blob, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func = NULL);
bool load_multisig_tx_from_file(const std::string &filename, multisig_tx_set &exported_txs, std::function<bool(const multisig_tx_set&)> accept_func = NULL);
bool sign_multisig_tx_from_file(const std::string &filename, std::vector<crypto::hash> &txids, std::function<bool(const multisig_tx_set&)> accept_func);
bool sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto::hash> &txids);
bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector<crypto::hash> &txids);
- std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon);
- void discard_unmixable_outputs(bool trusted_daemon);
+ std::vector<pending_tx> create_unmixable_sweep_transactions();
+ void discard_unmixable_outputs();
bool check_connection(uint32_t *version = NULL, uint32_t timeout = 200000);
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments, uint64_t min_height = 0, const boost::optional<uint32_t>& subaddr_account = boost::none, const std::set<uint32_t>& subaddr_indices = {}) const;
@@ -996,10 +988,10 @@ namespace tools
*/
uint64_t get_approximate_blockchain_height() const;
uint64_t estimate_blockchain_height();
- std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct, bool trusted_daemon);
+ std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool unlocked, bool allow_rct);
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f) const;
- std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon);
- std::vector<size_t> select_available_mixable_outputs(bool trusted_daemon);
+ std::vector<size_t> select_available_unmixable_outputs();
+ std::vector<size_t> select_available_mixable_outputs();
size_t pop_best_value_from(const transfer_container &transfers, std::vector<size_t> &unused_dust_indices, const std::vector<size_t>& selected_transfers, bool smallest = false) const;
size_t pop_best_value(std::vector<size_t> &unused_dust_indices, const std::vector<size_t>& selected_transfers, bool smallest = false) const;
@@ -1081,10 +1073,13 @@ namespace tools
bool is_synced() const;
std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(const std::vector<std::pair<double, double>> &fee_levels);
- std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(uint64_t min_blob_size, uint64_t max_blob_size, const std::vector<uint64_t> &fees);
+ std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(uint64_t min_tx_weight, uint64_t max_tx_weight, const std::vector<uint64_t> &fees);
uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm = -1) const;
- uint64_t get_per_kb_fee() const;
+ uint64_t get_base_fee() const;
+ uint64_t get_fee_quantization_mask() const;
+ uint64_t get_min_ring_size() const;
+ uint64_t get_max_ring_size() const;
uint64_t adjust_mixin(uint64_t mixin) const;
uint32_t adjust_priority(uint32_t priority);
@@ -1158,10 +1153,10 @@ namespace tools
bool set_ring(const crypto::key_image &key_image, const std::vector<uint64_t> &outs, bool relative);
bool find_and_save_rings(bool force = true);
- bool blackball_output(const crypto::public_key &output);
- bool set_blackballed_outputs(const std::vector<crypto::public_key> &outputs, bool add = false);
- bool unblackball_output(const crypto::public_key &output);
- bool is_output_blackballed(const crypto::public_key &output) const;
+ bool blackball_output(const std::pair<uint64_t, uint64_t> &output);
+ bool set_blackballed_outputs(const std::vector<std::pair<uint64_t, uint64_t>> &outputs, bool add = false);
+ bool unblackball_output(const std::pair<uint64_t, uint64_t> &output);
+ bool is_output_blackballed(const std::pair<uint64_t, uint64_t> &output) const;
bool lock_keys_file();
bool unlock_keys_file();
@@ -1195,7 +1190,7 @@ namespace tools
void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false);
void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error);
void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added);
- uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers, bool trusted_daemon) const;
+ uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers) const;
bool prepare_file_names(const std::string& file_path);
void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height);
void process_outgoing(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height, uint64_t ts, uint64_t spent, uint64_t received, uint32_t subaddr_account, const std::set<uint32_t>& subaddr_indices);
@@ -1209,9 +1204,9 @@ namespace tools
void check_acc_out_precomp(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info) const;
void check_acc_out_precomp_once(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const;
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
- uint64_t get_upper_transaction_size_limit() const;
+ uint64_t get_upper_transaction_weight_limit() const;
std::vector<uint64_t> get_unspent_amounts_vector() const;
- uint64_t get_dynamic_per_kb_fee_estimate() const;
+ uint64_t get_dynamic_base_fee_estimate() const;
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const;
void set_spent(size_t idx, uint64_t height);
@@ -1241,6 +1236,9 @@ namespace tools
void cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const;
+ void setup_new_blockchain();
+ void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file);
+
cryptonote::account_base m_account;
boost::optional<epee::net_utils::http::login> m_daemon_login;
std::string m_daemon_address;
@@ -1266,7 +1264,7 @@ namespace tools
std::unordered_map<std::string, std::string> m_attributes;
std::vector<tools::wallet2::address_book_row> m_address_book;
std::pair<std::map<std::string, std::string>, std::vector<std::string>> m_account_tags;
- uint64_t m_upper_transaction_size_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
+ uint64_t m_upper_transaction_weight_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
const std::vector<std::vector<tools::wallet2::multisig_info>> *m_multisig_rescan_info;
const std::vector<std::vector<rct::key>> *m_multisig_rescan_k;
@@ -1274,6 +1272,7 @@ namespace tools
boost::mutex m_daemon_rpc_mutex;
+ bool m_trusted_daemon;
i_wallet2_callback* m_callback;
bool m_key_on_device;
cryptonote::network_type m_nettype;
@@ -1815,198 +1814,4 @@ namespace tools
//----------------------------------------------------------------------------------------------------
}
//----------------------------------------------------------------------------------------------------
- template<typename T>
- void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outs_count, const std::vector<size_t> &unused_transfers_indices,
- uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, bool trusted_daemon)
- {
- pending_tx ptx;
- cryptonote::transaction tx;
- transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx, ptx, trusted_daemon);
- }
-
- template<typename T>
- void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices,
- uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx, bool trusted_daemon)
- {
- using namespace cryptonote;
- // throw if attempting a transaction with no destinations
- THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
-
- THROW_WALLET_EXCEPTION_IF(m_multisig, error::wallet_internal_error, "Multisig wallets cannot spend non rct outputs");
-
- uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit();
- uint64_t needed_money = fee;
-
- // calculate total amount being sent to all destinations
- // throw if total amount overflows uint64_t
- for(auto& dt: dsts)
- {
- THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination);
- needed_money += dt.amount;
- THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_nettype);
- }
-
- // randomly select inputs for transaction
- // throw if requested send amount is greater than (unlocked) amount available to send
- std::vector<size_t> selected_transfers;
- uint64_t found_money = select_transfers(needed_money, unused_transfers_indices, selected_transfers, trusted_daemon);
- THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee);
-
- uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major;
- for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i)
- THROW_WALLET_EXCEPTION_IF(subaddr_account != *i, error::wallet_internal_error, "the tx uses funds from multiple accounts");
-
- typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
- typedef cryptonote::tx_source_entry::output_entry tx_output_entry;
-
- COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
- if(fake_outputs_count)
- {
- COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req);
- req.outs_count = fake_outputs_count + 1;// add one to make possible (if need) to skip real output key
- for(size_t idx: selected_transfers)
- {
- const transfer_container::const_iterator it = m_transfers.begin() + idx;
- THROW_WALLET_EXCEPTION_IF(it->m_tx.vout.size() <= it->m_internal_output_index, error::wallet_internal_error,
- "m_internal_output_index = " + std::to_string(it->m_internal_output_index) +
- " is greater or equal to outputs count = " + std::to_string(it->m_tx.vout.size()));
- req.amounts.push_back(it->amount());
- }
-
- m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_bin("/getrandom_outs.bin", req, daemon_resp, m_http_client, rpc_timeout);
- m_daemon_rpc_mutex.unlock();
- THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getrandom_outs.bin");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getrandom_outs.bin");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::get_random_outs_error, daemon_resp.status);
- THROW_WALLET_EXCEPTION_IF(daemon_resp.outs.size() != selected_transfers.size(), error::wallet_internal_error,
- "daemon returned wrong response for getrandom_outs.bin, wrong amounts count = " +
- std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(selected_transfers.size()));
-
- std::unordered_map<uint64_t, uint64_t> scanty_outs;
- for(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs: daemon_resp.outs)
- {
- if (amount_outs.outs.size() < fake_outputs_count)
- {
- scanty_outs[amount_outs.amount] = amount_outs.outs.size();
- }
- }
- THROW_WALLET_EXCEPTION_IF(!scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
- }
-
- //prepare inputs
- size_t i = 0;
- std::vector<cryptonote::tx_source_entry> sources;
- for(size_t idx: selected_transfers)
- {
- sources.resize(sources.size()+1);
- cryptonote::tx_source_entry& src = sources.back();
- const transfer_details& td = m_transfers[idx];
- src.amount = td.amount();
- src.rct = false;
- //paste mixin transaction
- if(daemon_resp.outs.size())
- {
- daemon_resp.outs[i].outs.sort([](const out_entry& a, const out_entry& b){return a.global_amount_index < b.global_amount_index;});
- for(out_entry& daemon_oe: daemon_resp.outs[i].outs)
- {
- if(td.m_global_output_index == daemon_oe.global_amount_index)
- continue;
- tx_output_entry oe;
- oe.first = daemon_oe.global_amount_index;
- oe.second.dest = rct::pk2rct(daemon_oe.out_key);
- oe.second.mask = rct::identity();
- src.outputs.push_back(oe);
- if(src.outputs.size() >= fake_outputs_count)
- break;
- }
- }
-
- //paste real transaction to the random index
- auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a)
- {
- return a.first >= td.m_global_output_index;
- });
- //size_t real_index = src.outputs.size() ? (rand() % src.outputs.size() ):0;
- tx_output_entry real_oe;
- real_oe.first = td.m_global_output_index;
- real_oe.second.dest = rct::pk2rct(boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
- real_oe.second.mask = rct::identity();
- auto interted_it = src.outputs.insert(it_to_insert, real_oe);
- src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx);
- src.real_output = interted_it - src.outputs.begin();
- src.real_output_in_tx_index = td.m_internal_output_index;
- src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()});
- detail::print_source_entry(src);
- ++i;
- }
-
- cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
- if (needed_money < found_money)
- {
- change_dts.addr = get_subaddress({subaddr_account, 0});
- change_dts.amount = found_money - needed_money;
- }
-
- std::vector<cryptonote::tx_destination_entry> splitted_dsts, dust_dsts;
- uint64_t dust = 0;
- destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts);
- for(auto& d: dust_dsts) {
- THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " +
- std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold));
- }
- for(auto& d: dust_dsts) {
- if (!dust_policy.add_to_fee)
- splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust, d.is_subaddress));
- dust += d.amount;
- }
-
- crypto::secret_key tx_key;
- std::vector<crypto::secret_key> additional_tx_keys;
- rct::multisig_out msout;
- bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, false, m_multisig ? &msout : NULL);
- THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype);
- THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
-
- std::string key_images;
- bool all_are_txin_to_key = std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool
- {
- CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key, in, false);
- key_images += boost::to_string(in.k_image) + " ";
- return true;
- });
- THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx);
-
- bool dust_sent_elsewhere = (dust_policy.addr_for_dust.m_view_public_key != change_dts.addr.m_view_public_key
- || dust_policy.addr_for_dust.m_spend_public_key != change_dts.addr.m_spend_public_key);
-
- if (dust_policy.add_to_fee || dust_sent_elsewhere) change_dts.amount -= dust;
-
- ptx.key_images = key_images;
- ptx.fee = (dust_policy.add_to_fee ? fee+dust : fee);
- ptx.dust = ((dust_policy.add_to_fee || dust_sent_elsewhere) ? dust : 0);
- ptx.dust_added_to_fee = dust_policy.add_to_fee;
- ptx.tx = tx;
- ptx.change_dts = change_dts;
- ptx.selected_transfers = selected_transfers;
- ptx.tx_key = tx_key;
- ptx.additional_tx_keys = additional_tx_keys;
- ptx.dests = dsts;
- ptx.construction_data.sources = sources;
- ptx.construction_data.change_dts = change_dts;
- ptx.construction_data.splitted_dsts = splitted_dsts;
- ptx.construction_data.selected_transfers = selected_transfers;
- ptx.construction_data.extra = tx.extra;
- ptx.construction_data.unlock_time = unlock_time;
- ptx.construction_data.use_rct = false;
- ptx.construction_data.use_bulletproofs = false;
- ptx.construction_data.dests = dsts;
- // record which subaddress indices are being used as inputs
- ptx.construction_data.subaddr_account = subaddr_account;
- ptx.construction_data.subaddr_indices.clear();
- for (size_t idx: selected_transfers)
- ptx.construction_data.subaddr_indices.insert(m_transfers[idx].m_subaddr_index.minor);
- }
-
-
}
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index 243953280..bc518d04a 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -73,7 +73,7 @@ namespace tools
// get_tx_pool_error
// out_of_hashchain_bounds_error
// transfer_error *
- // get_random_outs_general_error
+ // get_outs_general_error
// not_enough_unlocked_money
// not_enough_money
// tx_not_possible
@@ -128,7 +128,7 @@ namespace tools
get_blocks_error_message_index,
get_hashes_error_message_index,
get_out_indices_error_message_index,
- get_random_outs_error_message_index
+ get_outs_error_message_index
};
template<typename Base, int msg_index>
@@ -427,7 +427,7 @@ namespace tools
}
};
//----------------------------------------------------------------------------------------------------
- typedef failed_rpc_request<transfer_error, get_random_outs_error_message_index> get_random_outs_error;
+ typedef failed_rpc_request<transfer_error, get_outs_error_message_index> get_outs_error;
//----------------------------------------------------------------------------------------------------
struct not_enough_unlocked_money : public transfer_error
{
@@ -679,30 +679,30 @@ namespace tools
//----------------------------------------------------------------------------------------------------
struct tx_too_big : public transfer_error
{
- explicit tx_too_big(std::string&& loc, const cryptonote::transaction& tx, uint64_t tx_size_limit)
+ explicit tx_too_big(std::string&& loc, const cryptonote::transaction& tx, uint64_t tx_weight_limit)
: transfer_error(std::move(loc), "transaction is too big")
, m_tx(tx)
- , m_tx_size_limit(tx_size_limit)
+ , m_tx_weight_limit(tx_weight_limit)
{
}
const cryptonote::transaction& tx() const { return m_tx; }
- uint64_t tx_size_limit() const { return m_tx_size_limit; }
+ uint64_t tx_weight_limit() const { return m_tx_weight_limit; }
std::string to_string() const
{
std::ostringstream ss;
cryptonote::transaction tx = m_tx;
ss << transfer_error::to_string() <<
- ", tx_size_limit = " << m_tx_size_limit <<
- ", tx size = " << get_object_blobsize(m_tx) <<
+ ", tx_weight_limit = " << m_tx_weight_limit <<
+ ", tx weight = " << get_transaction_weight(m_tx) <<
", tx:\n" << cryptonote::obj_to_json_str(tx);
return ss.str();
}
private:
cryptonote::transaction m_tx;
- uint64_t m_tx_size_limit;
+ uint64_t m_tx_weight_limit;
};
//----------------------------------------------------------------------------------------------------
struct zero_destination : public transfer_error
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 45bc0a1f3..ee86587bc 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -59,7 +59,6 @@ namespace
{
const command_line::arg_descriptor<std::string, true> arg_rpc_bind_port = {"rpc-bind-port", "Sets bind port for server"};
const command_line::arg_descriptor<bool> arg_disable_rpc_login = {"disable-rpc-login", "Disable HTTP authentication for RPC connections served by this process"};
- const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", "Enable commands which rely on a trusted daemon", false};
const command_line::arg_descriptor<bool> arg_restricted = {"restricted-rpc", "Restricts to view-only commands", false};
const command_line::arg_descriptor<std::string> arg_wallet_dir = {"wallet-dir", "Directory for newly created wallets"};
const command_line::arg_descriptor<bool> arg_prompt_for_password = {"prompt-for-password", "Prompts for password when not provided", false};
@@ -100,7 +99,7 @@ namespace tools
}
//------------------------------------------------------------------------------------------------------------------------------
- wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_file(), m_stop(false), m_trusted_daemon(false), m_restricted(false), m_vm(NULL)
+ wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_file(), m_stop(false), m_restricted(false), m_vm(NULL)
{
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -120,7 +119,7 @@ namespace tools
m_stop = false;
m_net_server.add_idle_handler([this](){
try {
- if (m_wallet) m_wallet->refresh(m_trusted_daemon);
+ if (m_wallet) m_wallet->refresh(m_wallet->is_trusted_daemon());
} catch (const std::exception& ex) {
LOG_ERROR("Exception at while refreshing, what=" << ex.what());
}
@@ -156,28 +155,10 @@ namespace tools
return false;
m_vm = vm;
- tools::wallet2 *walvars;
- std::unique_ptr<tools::wallet2> tmpwal;
- if (m_wallet)
- walvars = m_wallet;
- else
- {
- tmpwal = tools::wallet2::make_dummy(*m_vm, true, password_prompter);
- walvars = tmpwal.get();
- }
boost::optional<epee::net_utils::http::login> http_login{};
std::string bind_port = command_line::get_arg(*m_vm, arg_rpc_bind_port);
const bool disable_auth = command_line::get_arg(*m_vm, arg_disable_rpc_login);
- m_trusted_daemon = command_line::get_arg(*m_vm, arg_trusted_daemon);
- if (!command_line::has_arg(*m_vm, arg_trusted_daemon))
- {
- if (tools::is_local_address(walvars->get_daemon_address()))
- {
- MINFO(tr("Daemon is local, assuming trusted"));
- m_trusted_daemon = true;
- }
- }
m_restricted = command_line::get_arg(*m_vm, arg_restricted);
if (!command_line::is_arg_defaulted(*m_vm, arg_wallet_dir))
{
@@ -862,7 +843,7 @@ namespace tools
mixin = m_wallet->adjust_mixin(req.mixin);
}
uint32_t priority = m_wallet->adjust_priority(req.priority);
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
if (ptx_vector.empty())
{
@@ -923,7 +904,7 @@ namespace tools
}
uint32_t priority = m_wallet->adjust_priority(req.priority);
LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
@@ -1084,7 +1065,7 @@ namespace tools
try
{
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions();
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
@@ -1132,7 +1113,7 @@ namespace tools
mixin = m_wallet->adjust_mixin(req.mixin);
}
uint32_t priority = m_wallet->adjust_priority(req.priority);
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices);
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
@@ -1188,7 +1169,7 @@ namespace tools
mixin = m_wallet->adjust_mixin(req.mixin);
}
uint32_t priority = m_wallet->adjust_priority(req.priority);
- std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, priority, extra, m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, priority, extra);
if (ptx_vector.empty())
{
@@ -1557,7 +1538,6 @@ namespace tools
rpc_transfers.spent = td.m_spent;
rpc_transfers.global_index = td.m_global_output_index;
rpc_transfers.tx_hash = epee::string_tools::pod_to_hex(td.m_txid);
- rpc_transfers.tx_size = txBlob.size();
rpc_transfers.subaddr_index = td.m_subaddr_index.minor;
rpc_transfers.key_image = req.verbose && td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : "";
res.transfers.push_back(rpc_transfers);
@@ -2309,7 +2289,7 @@ namespace tools
er.message = "Command unavailable in restricted mode.";
return false;
}
- if (!m_trusted_daemon)
+ if (!m_wallet->is_trusted_daemon())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "This command requires a trusted daemon.";
@@ -2523,7 +2503,7 @@ namespace tools
}
try
{
- m_wallet->refresh(m_trusted_daemon, req.start_height, res.blocks_fetched, res.received_money);
+ m_wallet->refresh(m_wallet->is_trusted_daemon(), req.start_height, res.blocks_fetched, res.received_money);
return true;
}
catch (const std::exception& e)
@@ -2559,7 +2539,7 @@ namespace tools
bool wallet_rpc_server::on_start_mining(const wallet_rpc::COMMAND_RPC_START_MINING::request& req, wallet_rpc::COMMAND_RPC_START_MINING::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
- if (!m_trusted_daemon)
+ if (!m_wallet->is_trusted_daemon())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "This command requires a trusted daemon.";
@@ -2693,8 +2673,20 @@ namespace tools
er.message = "Failed to generate wallet";
return false;
}
+
if (m_wallet)
+ {
+ try
+ {
+ m_wallet->store();
+ }
+ catch (const std::exception& e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
delete m_wallet;
+ }
m_wallet = wal.release();
return true;
}
@@ -2751,12 +2743,74 @@ namespace tools
er.message = "Failed to open wallet";
return false;
}
+
if (m_wallet)
+ {
+ try
+ {
+ m_wallet->store();
+ }
+ catch (const std::exception& e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
delete m_wallet;
+ }
m_wallet = wal.release();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_close_wallet(const wallet_rpc::COMMAND_RPC_CLOSE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CLOSE_WALLET::response& res, epee::json_rpc::error& er)
+ {
+ if (!m_wallet) return not_open(er);
+
+ try
+ {
+ m_wallet->store();
+ }
+ catch (const std::exception& e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+ delete m_wallet;
+ m_wallet = NULL;
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_change_wallet_password(const wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD::request& req, wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD::response& res, epee::json_rpc::error& er)
+ {
+ if (!m_wallet) return not_open(er);
+ if (m_restricted)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_DENIED;
+ er.message = "Command unavailable in restricted mode.";
+ return false;
+ }
+ if (m_wallet->verify_password(req.old_password))
+ {
+ try
+ {
+ m_wallet->rewrite(m_wallet->get_wallet_file(), req.new_password);
+ m_wallet->store();
+ LOG_PRINT_L0("Wallet password changed.");
+ }
+ catch (const std::exception& e)
+ {
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
+ return false;
+ }
+ }
+ else
+ {
+ er.code = WALLET_RPC_ERROR_CODE_INVALID_PASSWORD;
+ er.message = "Invalid original password.";
+ return false;
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::handle_rpc_exception(const std::exception_ptr& e, epee::json_rpc::error& er, int default_error_code) {
try
{
@@ -2998,7 +3052,7 @@ namespace tools
return false;
}
- if (m_trusted_daemon)
+ if (m_wallet->is_trusted_daemon())
{
try
{
@@ -3221,7 +3275,6 @@ int main(int argc, char** argv) {
tools::wallet2::init_options(desc_params);
command_line::add_arg(desc_params, arg_rpc_bind_port);
command_line::add_arg(desc_params, arg_disable_rpc_login);
- command_line::add_arg(desc_params, arg_trusted_daemon);
command_line::add_arg(desc_params, arg_restricted);
cryptonote::rpc_args::init_options(desc_params);
command_line::add_arg(desc_params, arg_wallet_file);
@@ -3314,7 +3367,7 @@ int main(int argc, char** argv) {
wal->stop();
});
- wal->refresh(command_line::get_arg(*vm, arg_trusted_daemon));
+ wal->refresh(wal->is_trusted_daemon());
// if we ^C during potentially length load/refresh, there's no server loop yet
if (quit)
{
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index bfe49a459..ab7917a78 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -133,6 +133,8 @@ namespace tools
MAP_JON_RPC_WE("get_languages", on_get_languages, wallet_rpc::COMMAND_RPC_GET_LANGUAGES)
MAP_JON_RPC_WE("create_wallet", on_create_wallet, wallet_rpc::COMMAND_RPC_CREATE_WALLET)
MAP_JON_RPC_WE("open_wallet", on_open_wallet, wallet_rpc::COMMAND_RPC_OPEN_WALLET)
+ MAP_JON_RPC_WE("close_wallet", on_close_wallet, wallet_rpc::COMMAND_RPC_CLOSE_WALLET)
+ MAP_JON_RPC_WE("change_wallet_password", on_change_wallet_password, wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD)
MAP_JON_RPC_WE("is_multisig", on_is_multisig, wallet_rpc::COMMAND_RPC_IS_MULTISIG)
MAP_JON_RPC_WE("prepare_multisig", on_prepare_multisig, wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG)
MAP_JON_RPC_WE("make_multisig", on_make_multisig, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG)
@@ -208,6 +210,8 @@ namespace tools
bool on_get_languages(const wallet_rpc::COMMAND_RPC_GET_LANGUAGES::request& req, wallet_rpc::COMMAND_RPC_GET_LANGUAGES::response& res, epee::json_rpc::error& er);
bool on_create_wallet(const wallet_rpc::COMMAND_RPC_CREATE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CREATE_WALLET::response& res, epee::json_rpc::error& er);
bool on_open_wallet(const wallet_rpc::COMMAND_RPC_OPEN_WALLET::request& req, wallet_rpc::COMMAND_RPC_OPEN_WALLET::response& res, epee::json_rpc::error& er);
+ bool on_close_wallet(const wallet_rpc::COMMAND_RPC_CLOSE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CLOSE_WALLET::response& res, epee::json_rpc::error& er);
+ bool on_change_wallet_password(const wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD::request& req, wallet_rpc::COMMAND_RPC_CHANGE_WALLET_PASSWORD::response& res, epee::json_rpc::error& er);
bool on_is_multisig(const wallet_rpc::COMMAND_RPC_IS_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IS_MULTISIG::response& res, epee::json_rpc::error& er);
bool on_prepare_multisig(const wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::response& res, epee::json_rpc::error& er);
bool on_make_multisig(const wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::response& res, epee::json_rpc::error& er);
@@ -238,7 +242,6 @@ namespace tools
std::string m_wallet_dir;
tools::private_file rpc_login_file;
std::atomic<bool> m_stop;
- bool m_trusted_daemon;
bool m_restricted;
const boost::program_options::variables_map *m_vm;
};
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 3f946eaed..4501cf575 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 2
+#define WALLET_RPC_VERSION_MINOR 3
#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
@@ -445,7 +445,6 @@ namespace wallet_rpc
{
std::string tx_hash;
std::string tx_key;
- std::list<std::string> amount_keys;
uint64_t amount;
uint64_t fee;
std::string tx_blob;
@@ -456,7 +455,6 @@ namespace wallet_rpc
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(tx_key)
- KV_SERIALIZE(amount_keys)
KV_SERIALIZE(amount)
KV_SERIALIZE(fee)
KV_SERIALIZE(tx_blob)
@@ -768,15 +766,9 @@ namespace wallet_rpc
struct response
{
std::string tx_hash;
- std::string tx_key;
- uint64_t fee;
- std::string tx_blob;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
- KV_SERIALIZE(tx_key)
- KV_SERIALIZE(fee)
- KV_SERIALIZE(tx_blob)
END_KV_SERIALIZE_MAP()
};
};
@@ -867,7 +859,6 @@ namespace wallet_rpc
bool spent;
uint64_t global_index;
std::string tx_hash;
- uint64_t tx_size;
uint32_t subaddr_index;
std::string key_image;
@@ -876,7 +867,6 @@ namespace wallet_rpc
KV_SERIALIZE(spent)
KV_SERIALIZE(global_index)
KV_SERIALIZE(tx_hash)
- KV_SERIALIZE(tx_size)
KV_SERIALIZE(subaddr_index)
KV_SERIALIZE(key_image)
END_KV_SERIALIZE_MAP()
@@ -1831,6 +1821,40 @@ namespace wallet_rpc
};
};
+ struct COMMAND_RPC_CLOSE_WALLET
+ {
+ struct request
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_CHANGE_WALLET_PASSWORD
+ {
+ struct request
+ {
+ std::string old_password;
+ std::string new_password;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(old_password)
+ KV_SERIALIZE(new_password)
+ END_KV_SERIALIZE_MAP()
+ };
+ struct response
+ {
+ BEGIN_KV_SERIALIZE_MAP()
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
struct COMMAND_RPC_IS_MULTISIG
{
struct request