Compare commits

...

28 Commits

Author SHA1 Message Date
tobtoht
41ad5238a0
Merge pull request #10198
47345d1 CMake: override option with toolchain variable (tobtoht)
2025-11-26 20:43:27 +00:00
tobtoht
bf233c5652
Merge pull request #9203
b7b9bce simplewallet: edit desc. text for transfer (Cat)
2025-11-26 20:43:03 +00:00
tobtoht
481443039a
Merge pull request #10216
b03899f depends: boost: update to 1.89.0 (tobtoht)
2025-11-26 20:07:46 +00:00
Cat
b7b9bce9f7 simplewallet: edit desc. text for transfer 2025-11-26 20:04:40 +00:00
tobtoht
b3614d6b3f
Merge pull request #10170
ece0342 epee: align container pod as blob serialization (jeffro256)
2025-11-26 19:39:45 +00:00
tobtoht
b58280f3ec
Merge pull request #10231
4c4ffde depends: hidapi: update to 0.15.0 (tobtoht)
2025-11-26 19:34:38 +00:00
tobtoht
74b3e26ea1
Merge pull request #10184
0d1cf8f guix: remove libtool & python from darwin build env (tobtoht)
2025-11-26 19:33:41 +00:00
tobtoht
e1455fe373
Merge pull request #10217
b53c823 depends: drop unused patches (tobtoht)
2025-11-26 19:32:42 +00:00
tobtoht
662f0a6f32
Merge pull request #10215
d8d212c common: add std equivalent of hash_combine (jeffro256)
2025-11-26 19:32:06 +00:00
tobtoht
c66cf10629
Merge pull request #10197
7ef82eb guix: link libgcc_s statically for Linux targets (tobtoht)
2025-11-26 19:30:49 +00:00
tobtoht
483913506b
Merge pull request #10179
9e57f9b blockchain_prune: check DB version (jeffro256)
2025-11-26 18:49:08 +00:00
tobtoht
5fd71368db
Merge pull request #10214
a817da5 serialization: revert va_args_commaprefix usage (jeffro256)
2025-11-26 18:23:42 +00:00
tobtoht
337525d3d0
Merge pull request #10192
38bc627 Blockchain: cancel pop_blocks() operation on interupt (jeffro256)
2025-11-26 18:23:06 +00:00
tobtoht
ddfa2ed8fa
Merge pull request #10190
1347805 rpc: remove `COMMAND_RPC_SUBMIT_RAW_TX` (hinto.janai)
2025-11-26 18:22:31 +00:00
tobtoht
3eef33d8b3
Merge pull request #10188
acda1d4 p2p: unpack memory layout of peerlist entries (jeffro256)
2025-11-26 18:21:57 +00:00
tobtoht
4c4ffdedb0
depends: hidapi: update to 0.15.0 2025-11-24 17:31:39 +01:00
tobtoht
b53c823182
depends: drop unused patches 2025-11-13 22:00:26 +01:00
tobtoht
b03899f639
depends: boost: update to 1.89.0 2025-11-13 21:18:19 +01:00
jeffro256
d8d212ca42
common: add std equivalent of hash_combine 2025-11-13 11:59:57 -06:00
jeffro256
a817da5215
serialization: revert va_args_commaprefix usage 2025-11-13 11:48:13 -06:00
tobtoht
47345d14a2
CMake: override option with toolchain variable 2025-11-10 15:47:09 +01:00
tobtoht
7ef82ebc4b
guix: link libgcc_s statically for Linux targets 2025-11-10 15:17:41 +01:00
jeffro256
38bc62741b
Blockchain: cancel pop_blocks() operation on interupt
On SIGINT, `Blockchain::cancel()` is called, which sets `m_cancel` to `true`.
This commit stops attempting to pop blocks from the chain once that flag is
set. This should leave the blockchain in a well-define state, even if the
`pop_blocks()` operation itself did not "complete".
2025-11-07 13:21:00 -06:00
hinto.janai
1347805434
rpc: remove COMMAND_RPC_SUBMIT_RAW_TX 2025-11-06 23:29:45 +00:00
jeffro256
acda1d4a37
p2p: unpack memory layout of peerlist entries
The `#pragma pack(push, 1)` directive was causing unaligned memory
accesses to shared pointers in `epee::net_utils::network_address`.
The peerlist file uses Boost serialization, so this should be
backwards compatible.
2025-11-05 15:30:52 -06:00
tobtoht
0d1cf8f550
guix: remove libtool & python from darwin build env 2025-11-02 17:20:58 +01:00
jeffro256
9e57f9be83
blockchain_prune: check DB version
Prevents accidental future corruption of the database by refusing
to prune the DB before checking the version value inside the
properties table.
2025-10-27 18:11:54 -05:00
jeffro256
ece0342cb5
epee: align container pod as blob serialization
`{un}serialize_stl_container_pod_val_as_blob()` use aligned memory accesses on potentially unaligned pointers.
2025-10-14 16:05:43 -05:00
16 changed files with 134 additions and 112 deletions

View File

@ -43,6 +43,9 @@ include(CheckFunctionExists)
if (POLICY CMP0148)
cmake_policy(SET CMP0148 OLD) # https://cmake.org/cmake/help/latest/policy/CMP0148.html
endif()
if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif()
include(FindPythonInterp)
if (IOS)

View File

@ -1,8 +1,8 @@
package=boost
$(package)_version=1.84.0
$(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.bz2
$(package)_sha256_hash=cc4b893acf645c9d4b698e9a0f08ca8846aa5d6c68275c14c3e7949c24109454
$(package)_version=1.89.0
$(package)_download_path=https://github.com/boostorg/boost/releases/download/boost-$($(package)_version)
$(package)_file_name=boost-$($(package)_version)-b2-nodocs.tar.gz
$(package)_sha256_hash=aa25e7b9c227c21abb8a681efd4fe6e54823815ffc12394c9339de998eb503fb
define $(package)_set_vars
$(package)_config_opts_release=variant=release

View File

@ -1,8 +1,8 @@
package=hidapi
$(package)_version=0.14.0
$(package)_version=0.15.0
$(package)_download_path=https://github.com/libusb/hidapi/archive/refs/tags
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=a5714234abe6e1f53647dd8cba7d69f65f71c558b7896ed218864ffcf405bcbd
$(package)_sha256_hash=5d84dec684c27b97b921d2f3b73218cb773cf4ea915caee317ac8fc73cef8136
$(package)_linux_dependencies=libusb
# -DHIDAPI_NO_ICONV=ON

View File

@ -1,12 +0,0 @@
diff --git a/cctools/ld64/src/ld/Options.cpp b/cctools/ld64/src/ld/Options.cpp
index 3bb8324..033760d 100644
--- a/cctools/ld64/src/ld/Options.cpp
+++ b/cctools/ld64/src/ld/Options.cpp
@@ -4279,7 +4279,6 @@ void Options::buildSearchPaths(int argc, const char* argv[])
fVerbose = true;
extern const char ldVersionString[];
fprintf(stderr, "%s", ldVersionString);
- fprintf(stderr, "BUILD " __TIME__ " " __DATE__"\n");
fprintf(stderr, "configured to support archs: %s\n", ALL_SUPPORTED_ARCHS);
// if only -v specified, exit cleanly
if ( argc == 2 ) {

View File

@ -1,31 +0,0 @@
diff --git a/src/llvm/CMakeLists.txt b/src/llvm/CMakeLists.txt
index ab92717c8..4ad621ea3 100644
--- a/src/llvm/CMakeLists.txt
+++ b/src/llvm/CMakeLists.txt
@@ -752,9 +752,10 @@ set(LLVM_SRPM_USER_BINARY_SPECFILE ${CMAKE_CURRENT_SOURCE_DIR}/llvm.spec.in
set(LLVM_SRPM_BINARY_SPECFILE ${CMAKE_CURRENT_BINARY_DIR}/llvm.spec)
set(LLVM_SRPM_DIR "${CMAKE_CURRENT_BINARY_DIR}/srpm")
-# SVN_REVISION and GIT_COMMIT get set by the call to add_version_info_from_vcs.
-# DUMMY_VAR contains a version string which we don't care about.
-add_version_info_from_vcs(DUMMY_VAR)
+# A call to add_version_info_from_vcs() was removed, leaving SVN_REVISION
+# and GIT_COMMIT unset. Accordingly, LLVM_RPM_SPEC_REVISION is left empty.
+# This variable appears to be unused. Since it may be used in a future
+# update of native_libtapi this change serves as a precautionairy measure.
if ( SVN_REVISION )
set(LLVM_RPM_SPEC_REVISION "r${SVN_REVISION}")
elseif ( GIT_COMMIT )
diff --git a/src/llvm/cmake/modules/GenerateVersionFromCVS.cmake b/src/llvm/cmake/modules/GenerateVersionFromCVS.cmake
index 6b1c71983..e16326ed6 100644
--- a/src/llvm/cmake/modules/GenerateVersionFromCVS.cmake
+++ b/src/llvm/cmake/modules/GenerateVersionFromCVS.cmake
@@ -24,7 +24,7 @@ include(VersionFromVCS)
set(ENV{TERM} "dumb")
function(append_info name path)
- add_version_info_from_vcs(REVISION ${path})
+ set(REVISION "git-0000000")
string(STRIP "${REVISION}" REVISION)
file(APPEND "${HEADER_FILE}.txt"
"#define ${name} \"${REVISION}\"\n")

View File

@ -117,11 +117,11 @@ namespace epee
if(!container.size()) return true;
std::string mb;
mb.resize(sizeof(typename stl_container::value_type)*container.size());
typename stl_container::value_type* p_elem = (typename stl_container::value_type*)mb.data();
char *p_elem = mb.data();
BOOST_FOREACH(const typename stl_container::value_type& v, container)
{
*p_elem = v;
p_elem++;
memcpy(p_elem, std::addressof(v), sizeof(typename stl_container::value_type));
p_elem += sizeof(typename stl_container::value_type);
}
return stg.set_value(pname, std::move(mb), hparent_section);
}
@ -135,14 +135,19 @@ namespace epee
if(res)
{
size_t loaded_size = buff.size();
typename stl_container::value_type* pelem = (typename stl_container::value_type*)buff.data();
char *pelem = buff.data();
CHECK_AND_ASSERT_MES(!(loaded_size%sizeof(typename stl_container::value_type)),
false,
"size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type) << ", type " << typeid(typename stl_container::value_type).name());
size_t count = (loaded_size/sizeof(typename stl_container::value_type));
hint_resize(container, count);
for(size_t i = 0; i < count; i++)
container.insert(container.end(), *(pelem++));
{
typename stl_container::value_type v;
memcpy(std::addressof(v), pelem, sizeof(v));
container.insert(container.end(), v);
pelem += sizeof(v);
}
}
return res;
}

View File

@ -296,7 +296,7 @@ esac
# LDFLAGS
case "$HOST" in
*linux-gnu*) HOST_LDFLAGS="-Wl,--as-needed -Wl,--dynamic-linker=$glibc_dynamic_linker -static-libstdc++" ;;
*linux-gnu*) HOST_LDFLAGS="-Wl,--as-needed -Wl,--dynamic-linker=$glibc_dynamic_linker -static-libstdc++ -static-libgcc" ;;
*mingw*) HOST_LDFLAGS="-Wl,--no-insert-timestamp" ;;
esac

View File

@ -1,5 +1,4 @@
(use-modules (gnu packages)
((gnu packages autotools) #:select (libtool))
(gnu packages bash)
((gnu packages cmake) #:select (cmake-minimal))
(gnu packages commencement)
@ -12,7 +11,6 @@
(gnu packages mingw)
(gnu packages perl)
(gnu packages pkg-config)
((gnu packages python) #:select (python-minimal))
((gnu packages version-control) #:select (git-minimal))
(guix build-system gnu)
(guix build-system trivial)
@ -293,8 +291,6 @@ chain for " target " development."))
(list gcc-toolchain-12 "static")))
((string-contains target "darwin")
(list
libtool
python-minimal ; required to build libtapi in depends
gcc-toolchain-12
clang-toolchain-18
lld-18

View File

@ -53,6 +53,8 @@ static std::string db_path;
static uint64_t records_per_sync = 16 * 65536;
static const size_t slack = 512 * 1024 * 1024;
static constexpr uint32_t MAX_SUPPORTED_DB_VERSION = 5;
static std::vector<bool> is_v1;
static std::error_code replace_file(const boost::filesystem::path& replacement_name, const boost::filesystem::path& replaced_name)
@ -158,6 +160,46 @@ static bool resize_point(size_t &nrecords, MDB_env *env, MDB_txn **txn, size_t &
return true;
}
static uint32_t get_blockchain_db_version(MDB_env *env)
{
MDB_dbi properties_dbi;
MDB_txn *txn;
bool tx_active = false;
int rc;
MDB_val k;
MDB_val v;
uint32_t db_version = std::numeric_limits<uint32_t>::max();
const epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){
if (tx_active) mdb_txn_abort(txn);
});
// Setup tx and database index
rc = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
if (rc) throw std::runtime_error("Failed to create LMDB transaction: " + std::string(mdb_strerror(rc)));
tx_active = true;
rc = mdb_dbi_open(txn, "properties", /*flags=*/0, &properties_dbi);
if (rc) throw std::runtime_error("Failed to open LMDB properties dbi: " + std::string(mdb_strerror(rc)));
mdb_set_compare(txn, properties_dbi, BlockchainLMDB::compare_string);
// Fetch version
char VERSION_KEY[] = "version";
k.mv_data = reinterpret_cast<void*>(VERSION_KEY);
k.mv_size = sizeof(VERSION_KEY); // yes, this includes the null terminator
v = {};
rc = mdb_get(txn, properties_dbi, &k, &v);
if (rc) throw std::runtime_error("Failed to get version from properties table: " + std::string(mdb_strerror(rc)));
if (v.mv_data == nullptr || v.mv_size != sizeof(db_version))
throw std::runtime_error("Fetched version entry is wrong size");
memcpy(&db_version, v.mv_data, sizeof(db_version));
// Close tx
tx_active = false;
mdb_txn_commit(txn);
return db_version;
}
static void copy_table(MDB_env *env0, MDB_env *env1, const char *table, unsigned int flags, unsigned int putflags, int (*cmp)(const MDB_val*, const MDB_val*)=0, void (*f)(const MDB_val&, const MDB_val&) = 0)
{
MDB_dbi dbi0, dbi1;
@ -633,10 +675,23 @@ int main(int argc, char* argv[])
core_storage[1]->blockchain.deinit();
core_storage[1].reset(NULL);
MINFO("Pruning...");
MINFO("Opening source database...");
MDB_env *env0 = NULL, *env1 = NULL;
open(env0, paths[0], db_flags, true);
const uint32_t db_version = get_blockchain_db_version(env0);
MDEBUG("Blockchain DB has version " << db_version);
if (db_version > MAX_SUPPORTED_DB_VERSION)
{
MERROR("Source database has unrecognized blockchain DB version " << db_version
<< ". Code for blockchain_prune may need to be updated.");
close(env0);
return 1;
}
MINFO("Opening target database...");
open(env1, paths[1], db_flags, false);
MINFO("Copying unpruned tables...");
copy_table(env0, env1, "blocks", MDB_INTEGERKEY, 0);
copy_table(env0, env1, "block_info", MDB_INTEGERKEY | MDB_DUPSORT| MDB_DUPFIXED, 0, BlockchainLMDB::compare_uint64);
copy_table(env0, env1, "block_heights", MDB_INTEGERKEY | MDB_DUPSORT| MDB_DUPFIXED, 0, BlockchainLMDB::compare_hash32);
@ -656,11 +711,13 @@ int main(int argc, char* argv[])
copy_table(env0, env1, "properties", 0, 0, BlockchainLMDB::compare_string);
if (already_pruned)
{
MINFO("Copying already-pruned tables...");
copy_table(env0, env1, "txs_prunable", MDB_INTEGERKEY, 0, BlockchainLMDB::compare_uint64);
copy_table(env0, env1, "txs_prunable_tip", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, 0, BlockchainLMDB::compare_uint64);
}
else
{
MINFO("Pruning...");
prune(env0, env1);
}
close(env1);

48
src/common/hash_combine.h Normal file
View File

@ -0,0 +1,48 @@
// Copyright (c) 2025, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
//local headers
//third party headers
//standard headers
#include <functional>
//forward declarations
namespace tools
{
template <typename T>
void hash_combine(std::size_t &seed, T const& v)
{
// see boost::hash_combine()
seed ^= std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
} //namespace tools

View File

@ -33,13 +33,3 @@
#define PP_THIRD_ARG(a,b,c,...) c
#define VA_OPT_SUPPORTED_I(...) PP_THIRD_ARG(__VA_OPT__(,),true,false,)
#define VA_OPT_SUPPORTED VA_OPT_SUPPORTED_I(?)
// VA_ARGS_COMMAPREFIX(): VA_ARGS_COMMAPREFIX(__VA_ARGS__) expands to __VA_ARGS__ with a comma in
// front if more than one argument, else nothing.
// If __VA_OPT__ supported, use that. Else, use GCC's ,## hack
#if VA_OPT_SUPPORTED
# define VA_ARGS_COMMAPREFIX(...) __VA_OPT__(,) __VA_ARGS__
#else
# define VA_ARGS_COMMAPREFIX(...) , ## __VA_ARGS__
#endif

View File

@ -562,7 +562,7 @@ void Blockchain::pop_blocks(uint64_t nblocks)
const uint64_t blockchain_height = m_db->height();
if (blockchain_height > 0)
nblocks = std::min(nblocks, blockchain_height - 1);
while (i < nblocks)
while (i < nblocks && !m_cancel.load())
{
pop_block_from_blockchain();
++i;

View File

@ -54,8 +54,6 @@ namespace nodetool
s << std::hex << peer_id;
return epee::string_tools::pad_string(s.str(), 16, '0', true);
}
#pragma pack (push, 1)
template<typename AddressType>
struct peerlist_entry_base
@ -108,8 +106,6 @@ namespace nodetool
};
typedef anchor_peerlist_entry_base<epee::net_utils::network_address> anchor_peerlist_entry;
#pragma pack(pop)
inline
std::string print_peerlist_to_string(const std::vector<peerlist_entry>& pl)
{

View File

@ -355,36 +355,6 @@ inline const std::string get_rpc_status(const bool trusted_daemon, const std::st
typedef epee::misc_utils::struct_init<response_t> response;
};
//-----------------------------------------------
struct COMMAND_RPC_SUBMIT_RAW_TX
{
struct request_t
{
std::string address;
std::string view_key;
std::string tx;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(view_key)
KV_SERIALIZE(tx)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
struct response_t
{
std::string status;
std::string error;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(status)
KV_SERIALIZE(error)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
};
//-----------------------------------------------
struct COMMAND_RPC_GET_TRANSACTIONS
{
struct request_t: public rpc_access_request_base

View File

@ -191,9 +191,9 @@ inline auto do_serialize(Archive &ar, T &v, Args&&... args)
* VARINT_FIELD_F(). Otherwise, this macro is similar to
* BEGIN_SERIALIZE_OBJECT(), as you should list only field serializations.
*/
#define BEGIN_SERIALIZE_OBJECT_FN(stype, ...) \
template <bool W, template <bool> class Archive> \
bool do_serialize_object(Archive<W> &ar, stype &v VA_ARGS_COMMAPREFIX(__VA_ARGS__)) {
#define BEGIN_SERIALIZE_OBJECT_FN(stype) \
template <bool W, template <bool> class Archive> \
bool do_serialize_object(Archive<W> &ar, stype &v) {
/*! \macro PREPARE_CUSTOM_VECTOR_SERIALIZATION
*/
@ -211,10 +211,10 @@ inline auto do_serialize(Archive &ar, T &v, Args&&... args)
*
* \brief serializes a field \a f tagged \a t
*/
#define FIELD_N(t, f, ...) \
#define FIELD_N(t, f) \
do { \
ar.tag(t); \
bool r = do_serialize(ar, f VA_ARGS_COMMAPREFIX(__VA_ARGS__)); \
bool r = do_serialize(ar, f); \
if (!r || !ar.good()) return false; \
} while(0);
@ -233,7 +233,7 @@ inline auto do_serialize(Archive &ar, T &v, Args&&... args)
*
* \brief tags the field with the variable name and then serializes it (for use in a free function)
*/
#define FIELD_F(f, ...) FIELD_N(#f, v.f VA_ARGS_COMMAPREFIX(__VA_ARGS__))
#define FIELD_F(f) FIELD_N(#f, v.f)
/*! \macro FIELDS(f)
*

View File

@ -3211,7 +3211,7 @@ simple_wallet::simple_wallet()
tr("Show the blockchain height."));
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::on_command, this, &simple_wallet::transfer, _1),
tr(USAGE_TRANSFER),
tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included). The \"subtractfeefrom=\" list allows you to choose which destinations to fund the tx fee from instead of the change output. The fee will be split across the chosen destinations proportionally equally. For example, to make 3 transfers where the fee is taken from the first and third destinations, one could do: \"transfer <addr1> 3 <addr2> 0.5 <addr3> 1 subtractfeefrom=0,2\". Let's say the tx fee is 0.1. The balance would drop by exactly 4.5 XMR including fees, and addr1 & addr3 would receive 2.925 & 0.975 XMR, respectively. Use \"subtractfeefrom=all\" to spread the fee across all destinations."));
tr("Transfer <address> <amount>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included). The \"subtractfeefrom=\" list allows you to choose which destinations to fund the tx fee from instead of the change output. The fee will be split across the chosen destinations proportionally equally. For example, to make 3 transfers where the fee is taken from the first and third destinations, one could do: \"transfer <addr1> 3 <addr2> 0.5 <addr3> 1 subtractfeefrom=0,2\". Let's say the tx fee is 0.1. The balance would drop by exactly 4.5 XMR including fees, and addr1 & addr3 would receive 2.925 & 0.975 XMR, respectively. Use \"subtractfeefrom=all\" to spread the fee across all destinations."));
m_cmd_binder.set_handler("sweep_unmixable",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_unmixable, _1),
tr("Send all unmixable outputs to yourself with ring_size 1"));