Merge pull request #4401
66901901
README: harmonize command formatting inside README.md (Andrea)8cd98408
disable AES on s390x architecture (Tuan M. Hoang)4ed30bab
wallet: implement coin splitting for sweep_* 'outputs' option (whythat)24f52396
wallet: add 'outputs' option for sweep_* commands (whythat)52e19d69
README: Compile boost with cxxflags=-fPIC cflags=-fPIC (Italocoin Project)0c77523d
README: fill in libsodium package name for Arch (phloatingman)
This commit is contained in:
commit
85110b42ab
|
@ -154,6 +154,10 @@ if(ARCH_ID STREQUAL "powerpc")
|
||||||
set(PPC 1)
|
set(PPC 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ARCH_ID STREQUAL "s390x")
|
||||||
|
set(S390X 1)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32 OR ARM OR PPC64LE OR PPC64 OR PPC)
|
if(WIN32 OR ARM OR PPC64LE OR PPC64 OR PPC)
|
||||||
set(OPT_FLAGS_RELEASE "-O2")
|
set(OPT_FLAGS_RELEASE "-O2")
|
||||||
else()
|
else()
|
||||||
|
@ -641,12 +645,14 @@ else()
|
||||||
message(STATUS "AES support explicitly disabled")
|
message(STATUS "AES support explicitly disabled")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_AES")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNO_AES")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_AES")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_AES")
|
||||||
elseif(NOT ARM AND NOT PPC64LE AND NOT PPC64 AND NOT PPC)
|
elseif(NOT ARM AND NOT PPC64LE AND NOT PPC64 AND NOT PPC AND NOT S390X)
|
||||||
message(STATUS "AES support enabled")
|
message(STATUS "AES support enabled")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maes")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -maes")
|
||||||
elseif(PPC64LE OR PPC64 OR PPC)
|
elseif(PPC64LE OR PPC64 OR PPC)
|
||||||
message(STATUS "AES support not available on POWER")
|
message(STATUS "AES support not available on POWER")
|
||||||
|
elseif(S390X)
|
||||||
|
message(STATUS "AES support not available on s390x")
|
||||||
elseif(ARM6)
|
elseif(ARM6)
|
||||||
message(STATUS "AES support not available on ARMv6")
|
message(STATUS "AES support not available on ARMv6")
|
||||||
elseif(ARM7)
|
elseif(ARM7)
|
||||||
|
|
52
README.md
52
README.md
|
@ -118,6 +118,52 @@ X's indicate that these details have not been determined as of commit date.
|
||||||
|
|
||||||
Approximately three months prior to a scheduled software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
|
Approximately three months prior to a scheduled software upgrade, a branch from Master will be created with the new release version tag. Pull requests that address bugs should then be made to both Master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
|
||||||
|
|
||||||
|
<<<<<<< HEAD
|
||||||
|
=======
|
||||||
|
## Installing Monero from a package
|
||||||
|
|
||||||
|
Packages are available for
|
||||||
|
|
||||||
|
* Ubuntu and [snap supported](https://snapcraft.io/docs/core/install) systems, via a community contributed build.
|
||||||
|
|
||||||
|
snap install monero --beta
|
||||||
|
|
||||||
|
Installing a snap is very quick. Snaps are secure. They are isolated with all of their dependencies. Snaps also auto update when a new version is released.
|
||||||
|
|
||||||
|
* Arch Linux (via [AUR](https://aur.archlinux.org/)):
|
||||||
|
- Stable release: [`monero`](https://aur.archlinux.org/packages/monero)
|
||||||
|
- Bleeding edge: [`monero-git`](https://aur.archlinux.org/packages/monero-git)
|
||||||
|
|
||||||
|
* Void Linux:
|
||||||
|
|
||||||
|
xbps-install -S monero
|
||||||
|
|
||||||
|
* GuixSD
|
||||||
|
|
||||||
|
guix package -i monero
|
||||||
|
|
||||||
|
* OS X via [Homebrew](http://brew.sh)
|
||||||
|
|
||||||
|
brew tap sammy007/cryptonight
|
||||||
|
brew install monero --build-from-source
|
||||||
|
|
||||||
|
* Docker
|
||||||
|
|
||||||
|
# Build using all available cores
|
||||||
|
docker build -t monero .
|
||||||
|
|
||||||
|
# or build using a specific number of cores (reduce RAM requirement)
|
||||||
|
docker build --build-arg NPROC=1 -t monero .
|
||||||
|
|
||||||
|
# either run in foreground
|
||||||
|
docker run -it -v /monero/chain:/root/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
|
||||||
|
|
||||||
|
# or in background
|
||||||
|
docker run -it -d -v /monero/chain:/root/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
|
||||||
|
|
||||||
|
Packaging for your favorite distribution would be a welcome contribution!
|
||||||
|
|
||||||
|
>>>>>>> f6d62ab... Formating commands inside README.md
|
||||||
## Compiling Monero from source
|
## Compiling Monero from source
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
@ -141,7 +187,7 @@ library archives (`.a`).
|
||||||
| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | `cppzmq-devel` | NO | ZeroMQ library |
|
| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | `cppzmq-devel` | NO | ZeroMQ library |
|
||||||
| OpenPGM | ? | NO | `libpgm-dev` | `libpgm` | `openpgm-devel` | NO | For ZeroMQ |
|
| OpenPGM | ? | NO | `libpgm-dev` | `libpgm` | `openpgm-devel` | NO | For ZeroMQ |
|
||||||
| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | NO | DNS resolver |
|
| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | NO | DNS resolver |
|
||||||
| libsodium | ? | NO | `libsodium-dev` | ? | `libsodium-devel` | NO | cryptography |
|
| libsodium | ? | NO | `libsodium-dev` | `libsodium` | `libsodium-devel` | NO | cryptography |
|
||||||
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | YES | Stack traces |
|
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | YES | Stack traces |
|
||||||
| liblzma | any | NO | `liblzma-dev` | `xz` | `xz-devel` | YES | For libunwind |
|
| liblzma | any | NO | `liblzma-dev` | `xz` | `xz-devel` | YES | For libunwind |
|
||||||
| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | YES | Input editing |
|
| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | YES | Input editing |
|
||||||
|
@ -284,7 +330,7 @@ If you are using the older Raspbian Jessie image, compiling Monero is a bit more
|
||||||
```
|
```
|
||||||
* Wait ~8 hours
|
* Wait ~8 hours
|
||||||
```
|
```
|
||||||
sudo ./bjam install
|
sudo ./bjam cxxflags=-fPIC cflags=-fPIC -a install
|
||||||
```
|
```
|
||||||
* Wait ~4 hours
|
* Wait ~4 hours
|
||||||
|
|
||||||
|
@ -499,7 +545,7 @@ Packages are available for
|
||||||
|
|
||||||
* Ubuntu and [snap supported](https://snapcraft.io/docs/core/install) systems, via a community contributed build.
|
* Ubuntu and [snap supported](https://snapcraft.io/docs/core/install) systems, via a community contributed build.
|
||||||
|
|
||||||
snap install monero --beta
|
snap install monero --beta
|
||||||
|
|
||||||
Installing a snap is very quick. Snaps are secure. They are isolated with all of their dependencies. Snaps also auto update when a new version is released.
|
Installing a snap is very quick. Snaps are secure. They are isolated with all of their dependencies. Snaps also auto update when a new version is released.
|
||||||
|
|
||||||
|
|
|
@ -2311,15 +2311,15 @@ simple_wallet::simple_wallet()
|
||||||
boost::bind(&simple_wallet::sweep_unmixable, this, _1),
|
boost::bind(&simple_wallet::sweep_unmixable, this, _1),
|
||||||
tr("Send all unmixable outputs to yourself with ring_size 1"));
|
tr("Send all unmixable outputs to yourself with ring_size 1"));
|
||||||
m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1),
|
m_cmd_binder.set_handler("sweep_all", boost::bind(&simple_wallet::sweep_all, this, _1),
|
||||||
tr("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]"),
|
tr("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]"),
|
||||||
tr("Send all unlocked balance to an address. If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used."));
|
tr("Send all unlocked balance to an address. If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used. If the parameter \"outputs=<N>\" is specified and N > 0, wallet splits the transaction into N even outputs."));
|
||||||
m_cmd_binder.set_handler("sweep_below",
|
m_cmd_binder.set_handler("sweep_below",
|
||||||
boost::bind(&simple_wallet::sweep_below, this, _1),
|
boost::bind(&simple_wallet::sweep_below, this, _1),
|
||||||
tr("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]"),
|
tr("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]"),
|
||||||
tr("Send all unlocked outputs below the threshold to an address."));
|
tr("Send all unlocked outputs below the threshold to an address."));
|
||||||
m_cmd_binder.set_handler("sweep_single",
|
m_cmd_binder.set_handler("sweep_single",
|
||||||
boost::bind(&simple_wallet::sweep_single, this, _1),
|
boost::bind(&simple_wallet::sweep_single, this, _1),
|
||||||
tr("sweep_single [<priority>] [<ring_size>] <key_image> <address> [<payment_id>]"),
|
tr("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]"),
|
||||||
tr("Send a single output of the given key image to an address without change."));
|
tr("Send a single output of the given key image to an address without change."));
|
||||||
m_cmd_binder.set_handler("donate",
|
m_cmd_binder.set_handler("donate",
|
||||||
boost::bind(&simple_wallet::donate, this, _1),
|
boost::bind(&simple_wallet::donate, this, _1),
|
||||||
|
@ -5253,7 +5253,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
|
||||||
{
|
{
|
||||||
auto print_usage = [below]()
|
auto print_usage = [below]()
|
||||||
{
|
{
|
||||||
fail_msg_writer() << boost::format(tr("usage: %s [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]")) % (below ? "sweep_below" : "sweep_all");
|
fail_msg_writer() << boost::format(tr("usage: %s [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]")) % (below ? "sweep_below" : "sweep_all");
|
||||||
};
|
};
|
||||||
if (args_.size() == 0)
|
if (args_.size() == 0)
|
||||||
{
|
{
|
||||||
|
@ -5351,6 +5351,25 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
|
||||||
local_args.erase(local_args.begin() + 1);
|
local_args.erase(local_args.begin() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t outputs = 1;
|
||||||
|
if (local_args.size() > 0 && local_args[0].substr(0, 8) == "outputs=")
|
||||||
|
{
|
||||||
|
if (!epee::string_tools::get_xtype_from_string(outputs, local_args[0].substr(8)))
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Failed to parse number of outputs");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (outputs < 1)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Amount of outputs should be greater than 0");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
local_args.erase(local_args.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> extra;
|
std::vector<uint8_t> extra;
|
||||||
bool payment_id_seen = false;
|
bool payment_id_seen = false;
|
||||||
if (local_args.size() >= 2)
|
if (local_args.size() >= 2)
|
||||||
|
@ -5435,7 +5454,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// figure out what tx will be necessary
|
// figure out what tx will be necessary
|
||||||
auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
|
auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
|
||||||
|
|
||||||
if (ptx_vector.empty())
|
if (ptx_vector.empty())
|
||||||
{
|
{
|
||||||
|
@ -5576,6 +5595,25 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t outputs = 1;
|
||||||
|
if (local_args.size() > 0 && local_args[0].substr(0, 8) == "outputs=")
|
||||||
|
{
|
||||||
|
if (!epee::string_tools::get_xtype_from_string(outputs, local_args[0].substr(8)))
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Failed to parse number of outputs");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (outputs < 1)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Amount of outputs should be greater than 0");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
local_args.erase(local_args.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> extra;
|
std::vector<uint8_t> extra;
|
||||||
bool payment_id_seen = false;
|
bool payment_id_seen = false;
|
||||||
if (local_args.size() == 3)
|
if (local_args.size() == 3)
|
||||||
|
@ -5609,7 +5647,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||||
|
|
||||||
if (local_args.size() != 2)
|
if (local_args.size() != 2)
|
||||||
{
|
{
|
||||||
fail_msg_writer() << tr("usage: sweep_single [<priority>] [<ring_size>] <key_image> <address> [<payment_id>]");
|
fail_msg_writer() << tr("usage: sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5664,7 +5702,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// figure out what tx will be necessary
|
// figure out what tx will be necessary
|
||||||
auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra);
|
auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, outputs, fake_outs_count, 0 /* unlock_time */, priority, extra);
|
||||||
|
|
||||||
if (ptx_vector.empty())
|
if (ptx_vector.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -8464,7 +8464,7 @@ skip_tx:
|
||||||
return ptx_vector;
|
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)
|
std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, 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_transfers_indices;
|
||||||
std::vector<size_t> unused_dust_indices;
|
std::vector<size_t> unused_dust_indices;
|
||||||
|
@ -8515,10 +8515,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);
|
return create_transactions_from(address, is_subaddress, outputs, 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)
|
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 outputs, 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_transfers_indices;
|
||||||
std::vector<size_t> unused_dust_indices;
|
std::vector<size_t> unused_dust_indices;
|
||||||
|
@ -8536,10 +8536,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
|
return create_transactions_from(address, is_subaddress, outputs, 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)
|
std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, 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
|
//ensure device is let in NONE mode in any case
|
||||||
hw::device &hwdev = m_account.get_device();
|
hw::device &hwdev = m_account.get_device();
|
||||||
|
@ -8634,7 +8634,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
|
|
||||||
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);
|
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));
|
// add N - 1 outputs for correct initial fee estimation
|
||||||
|
for (size_t i = 0; i < ((outputs > 1) ? outputs - 1 : outputs); ++i)
|
||||||
|
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
|
||||||
|
|
||||||
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
|
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " <<
|
||||||
tx.selected_transfers.size() << " outputs");
|
tx.selected_transfers.size() << " outputs");
|
||||||
|
@ -8646,15 +8648,35 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||||
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx);
|
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);
|
auto txBlob = t_serializable_object_to_blob(test_ptx.tx);
|
||||||
needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_multiplier, fee_quantization_mask);
|
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;
|
available_for_fee = test_ptx.fee + test_ptx.change_dts.amount;
|
||||||
|
for (auto &dt: test_ptx.dests)
|
||||||
|
available_for_fee += dt.amount;
|
||||||
LOG_PRINT_L2("Made a " << get_weight_string(test_ptx.tx, txBlob.size()) << " 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)");
|
print_money(needed_fee) << " needed)");
|
||||||
|
|
||||||
|
// add last output, missed for fee estimation
|
||||||
|
if (outputs > 1)
|
||||||
|
tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress));
|
||||||
|
|
||||||
THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, "Transaction cannot pay for itself");
|
THROW_WALLET_EXCEPTION_IF(needed_fee > available_for_fee, error::wallet_internal_error, "Transaction cannot pay for itself");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
|
LOG_PRINT_L2("We made a tx, adjusting fee and saving it");
|
||||||
tx.dsts[0].amount = available_for_fee - needed_fee;
|
// distribute total transferred amount between outputs
|
||||||
|
uint64_t amount_transferred = available_for_fee - needed_fee;
|
||||||
|
uint64_t dt_amount = amount_transferred / outputs;
|
||||||
|
// residue is distributed as one atomic unit per output until it reaches zero
|
||||||
|
uint64_t residue = amount_transferred % outputs;
|
||||||
|
for (auto &dt: tx.dsts)
|
||||||
|
{
|
||||||
|
uint64_t dt_residue = 0;
|
||||||
|
if (residue > 0)
|
||||||
|
{
|
||||||
|
dt_residue = 1;
|
||||||
|
residue -= 1;
|
||||||
|
}
|
||||||
|
dt.amount = dt_amount + dt_residue;
|
||||||
|
}
|
||||||
if (use_rct)
|
if (use_rct)
|
||||||
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra,
|
||||||
test_tx, test_ptx, range_proof_type);
|
test_tx, test_ptx, range_proof_type);
|
||||||
|
@ -8901,7 +8923,7 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions()
|
||||||
unmixable_transfer_outputs.push_back(n);
|
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>());
|
return create_transactions_from(m_account_public_address, false, 1, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>());
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void wallet2::discard_unmixable_outputs()
|
void wallet2::discard_unmixable_outputs()
|
||||||
|
|
|
@ -752,9 +752,9 @@ namespace tools
|
||||||
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 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);
|
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<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_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_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, 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_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, 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);
|
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, 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(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 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_from_file(const std::string &filename, std::vector<crypto::hash> &txids, std::function<bool(const multisig_tx_set&)> accept_func);
|
||||||
|
|
|
@ -1102,6 +1102,13 @@ namespace tools
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.outputs < 1)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE;
|
||||||
|
er.message = "Amount of outputs should be greater than 0.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
uint64_t mixin;
|
uint64_t mixin;
|
||||||
|
@ -1114,7 +1121,7 @@ namespace tools
|
||||||
mixin = m_wallet->adjust_mixin(req.mixin);
|
mixin = m_wallet->adjust_mixin(req.mixin);
|
||||||
}
|
}
|
||||||
uint32_t priority = m_wallet->adjust_priority(req.priority);
|
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);
|
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, 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,
|
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);
|
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
|
||||||
|
@ -1140,6 +1147,13 @@ namespace tools
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.outputs < 1)
|
||||||
|
{
|
||||||
|
er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE;
|
||||||
|
er.message = "Amount of outputs should be greater than 0.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// validate the transfer requested and populate dsts & extra
|
// validate the transfer requested and populate dsts & extra
|
||||||
std::list<wallet_rpc::transfer_destination> destination;
|
std::list<wallet_rpc::transfer_destination> destination;
|
||||||
destination.push_back(wallet_rpc::transfer_destination());
|
destination.push_back(wallet_rpc::transfer_destination());
|
||||||
|
@ -1170,7 +1184,7 @@ namespace tools
|
||||||
mixin = m_wallet->adjust_mixin(req.mixin);
|
mixin = m_wallet->adjust_mixin(req.mixin);
|
||||||
}
|
}
|
||||||
uint32_t priority = m_wallet->adjust_priority(req.priority);
|
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);
|
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra);
|
||||||
|
|
||||||
if (ptx_vector.empty())
|
if (ptx_vector.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -639,6 +639,7 @@ namespace wallet_rpc
|
||||||
uint32_t priority;
|
uint32_t priority;
|
||||||
uint64_t mixin;
|
uint64_t mixin;
|
||||||
uint64_t ring_size;
|
uint64_t ring_size;
|
||||||
|
uint64_t outputs;
|
||||||
uint64_t unlock_time;
|
uint64_t unlock_time;
|
||||||
std::string payment_id;
|
std::string payment_id;
|
||||||
bool get_tx_keys;
|
bool get_tx_keys;
|
||||||
|
@ -654,6 +655,7 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE(priority)
|
KV_SERIALIZE(priority)
|
||||||
KV_SERIALIZE_OPT(mixin, (uint64_t)0)
|
KV_SERIALIZE_OPT(mixin, (uint64_t)0)
|
||||||
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
|
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
|
||||||
|
KV_SERIALIZE_OPT(outputs, (uint64_t)1)
|
||||||
KV_SERIALIZE(unlock_time)
|
KV_SERIALIZE(unlock_time)
|
||||||
KV_SERIALIZE(payment_id)
|
KV_SERIALIZE(payment_id)
|
||||||
KV_SERIALIZE(get_tx_keys)
|
KV_SERIALIZE(get_tx_keys)
|
||||||
|
@ -705,6 +707,7 @@ namespace wallet_rpc
|
||||||
uint32_t priority;
|
uint32_t priority;
|
||||||
uint64_t mixin;
|
uint64_t mixin;
|
||||||
uint64_t ring_size;
|
uint64_t ring_size;
|
||||||
|
uint64_t outputs;
|
||||||
uint64_t unlock_time;
|
uint64_t unlock_time;
|
||||||
std::string payment_id;
|
std::string payment_id;
|
||||||
bool get_tx_key;
|
bool get_tx_key;
|
||||||
|
@ -718,6 +721,7 @@ namespace wallet_rpc
|
||||||
KV_SERIALIZE(priority)
|
KV_SERIALIZE(priority)
|
||||||
KV_SERIALIZE_OPT(mixin, (uint64_t)0)
|
KV_SERIALIZE_OPT(mixin, (uint64_t)0)
|
||||||
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
|
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
|
||||||
|
KV_SERIALIZE_OPT(outputs, (uint64_t)1)
|
||||||
KV_SERIALIZE(unlock_time)
|
KV_SERIALIZE(unlock_time)
|
||||||
KV_SERIALIZE(payment_id)
|
KV_SERIALIZE(payment_id)
|
||||||
KV_SERIALIZE(get_tx_key)
|
KV_SERIALIZE(get_tx_key)
|
||||||
|
|
Loading…
Reference in New Issue