Compare commits

..

94 Commits

Author SHA1 Message Date
wowario 276fd65f2a
Update RandomWOW to 1.2.1-wow
7 months ago
j-berman 1e38c3c508
wallet2: ensure transfers and sweeps use same fee calc logic
7 months ago
jeffro256 1cb536ff45
http_client: reduce number of packets sent for small bodies
7 months ago
tobtoht 7737171b6c
depends: openssl: update to 3.0.11
7 months ago
selsta 1b8475003c
wallet2: fix refresh function parameters
7 months ago
Boog900 c1093aa33d
Fix: long term block weight cache
7 months ago
Boog900 650cef2279
add a test for the long term weight cache
7 months ago
wowario 3c329005f5
add more seeds
7 months ago
wowario 56b5d10b41
disable mismatched daemon check
7 months ago
wowario bae8df3f21
remove nudge in daemon_is_outdated
7 months ago
wowario 8f6e5fb500
[README] bump version
7 months ago
wowario b322839951
update checkpoints
7 months ago
wowario 1e5184a63a
remove nudge in num_mainnet_hard_forks
7 months ago
_XxFedexX_ 87be033224
Add _xxfedexx_'s PGP key
7 months ago
wowario c1488d7896
remove rx_set code
7 months ago
wowario 140a5e430a
use rx_set_miner_thread after RX_BLOCK_VERSION
7 months ago
thotbot 378e241ff6
Import transaction
7 months ago
wowario b403a4e6d4
show wallet info
7 months ago
hinto-janaiyo 35a6b6c825
simplewallet/wallet2: set option - show-detailed-prompt
7 months ago
moneromooo-monero bfc28a3bfe
blockchain_prune: faster
7 months ago
moneromooo-monero 27a9a417dc
simplewallet: print fully qualified filename for new wallets
7 months ago
thotbot e3d5e895cd
Misc. network related
7 months ago
thotbot 5b9e342966
Skip unneeded blocks in fast refresh
7 months ago
thotbot dc44ccad2d
subaddressIndex()
7 months ago
thotbot fad6c11b6f
Print wallet cache
7 months ago
thotbot 493608203f
Misc. wallet API and wallet2 changes
7 months ago
thotbot ce32e59844
Coins
7 months ago
thotbot c7c1558c1d
Offline transaction signing
7 months ago
wowario 176ed83a39
update checkpoints
7 months ago
wowario 51e192d2cc
connect to updated seeds
7 months ago
wowario 2ebf9fcfe9
add wowario PGP key
7 months ago
wowario 938420b2e6
Revoke old pgp key
7 months ago
wowario 4679496727
support old ass BPs
7 months ago
wowario 8780f9fb30
revert sanity check
7 months ago
wowario 7cd57d6479
wallet seed message spacing
7 months ago
wowario 6e22bcadd9
remove warning reusing keys
7 months ago
wowario 02c36da7e5
remove warning about background mining
7 months ago
wowario d3e753deb5
add clear screen command
7 months ago
wowario 487418b952
wownero chan
7 months ago
wowario 748d6a3184
update README.md
7 months ago
wowario 7ab0cbb19e
update checkpoints
7 months ago
wowario 31c5ba00d5
set fork height
7 months ago
wowario c80566ca00
from v20, limit tx extra size
7 months ago
wowario dcafb09415
Debug level No incoming connections
7 months ago
wowario ae54f2e737
update checkpoints
7 months ago
wowario e1f25be028
uri remainder
7 months ago
wowario 3b15bb4696
update README.md
7 months ago
wowario e00a7d1638
remove testnet/stagenet fork heights/blocks
7 months ago
wowario c69dc334fb
don't request pre-bulletprooof pruned blocks
7 months ago
wowario 89c0a9de4c
change to debug level
7 months ago
wowario 7174ff9bcb
rename ringdb-dir
7 months ago
wowario 0fc75eb44e
mod variant4_random_math
7 months ago
wowario fe05821c19
support old BP
7 months ago
wowario daddd7d231
vote by block
7 months ago
wowario 0871203167
tidy up miner msgs
7 months ago
wowario de2a8c65cf
miner block header signing
7 months ago
wowario 2e18be9977
difficulty is fun
7 months ago
wowario 67f16d765c
shorten timestamp check window
7 months ago
wowario d81ef76d7c
limit future blk time to 10 min
7 months ago
wowario 39809d46c6
bump unlock time to 288 blks
7 months ago
wowario 8243f192ab
broadcast donation sub-address
7 months ago
wowario bb391f0d00
revert Preserve commitment format inside transactions #8277
7 months ago
wowario 052e775d24
add systemd file
7 months ago
wowario 2adf97e0d3
update gitian
7 months ago
wowario b3ce01e702
update Dockerfile
7 months ago
wowario 6a6f6c1424
adjust approx_blockchain_height
7 months ago
wowario 9b2d897043
add wowario gpg key
7 months ago
wowario 37169ebb39
config wallet2 settings
7 months ago
wowario c92464e27f
set dev fund address
7 months ago
wowario ae7c139056
add seed nodes
7 months ago
wowario add841d552
set name of daemon stdout
7 months ago
wowario 31f59338d3
set last v1 block
7 months ago
wowario c9b8d94e83
set pow variants
7 months ago
wowario 8498370447
set quick height for syncing
7 months ago
wowario c1ef123bad
send dump log to wowario
7 months ago
wowario 065e89580f
set genesis block timestamp
7 months ago
wowario 5d369a5bf3
set decimal point
7 months ago
wowario 07e3c1a9b8
add forks and checkpoints
7 months ago
wowario ad27e5892b
wownero skin pack
7 months ago
wowario 10f22a4267
bump RX block version
7 months ago
wowario 3709b2684b
correct length of addresses
7 months ago
wowario 0901cd95c9
move utilities to debug build
7 months ago
wowario 67e03a315a
automatic submodule update
7 months ago
wowario 36edf137e4
Doxygen off
7 months ago
wowario f36d2f79b8
trezor support off
7 months ago
wowario d890edf7db
turn off tests
7 months ago
wowario 6e1158eaa4
gitian: copy config file
7 months ago
wowario d1387cbadc
add RandomWOW
7 months ago
wowario 82a019cd12
show full version
7 months ago
wowario b83ff851d2
remove moneropulse urls
7 months ago
wowario 95e7407aa1
remove monero tx bug fixes
7 months ago
wowario 5f6703f2c2
bump ring size to 22
7 months ago
wowario 4c6e685174
initialize genesis block
7 months ago
wowario 92ebb323e1
config cryptonote
7 months ago

@ -104,7 +104,7 @@ release-all:
release-static:
mkdir -p $(builddir)/release
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D USE_DEVICE_TREZOR=OFF -D STATIC=ON -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release $(topdir) && $(MAKE)
cd $(builddir)/release && cmake -D BUILD_TESTS=OFF -D USE_DEVICE_TREZOR=OFF -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release $(topdir) && $(MAKE)
coverage:
mkdir -p $(builddir)/debug

@ -1,12 +1,7 @@
# ~~Mo~~Wownero - Such privacy! Many coins! Wow!
# ~~Mo~~Wownero - Such privacy! Many coins! Wow! 🐕
[<img src="https://suchwow.xyz/data/suchwow/image/to23moqn.jpeg">](https://suchwow.xyz/s/oh-really-9eda16b2/item)
## Introduction
Wownero is a Doge-inspired, CPU-mineable, solo-mining only, privacy-respecting memecoin. It was fairly launched on April Fools' Day in 2018. It is a software fork of Monero, but with a lite version of RandomX, larger ring size, and a fixed supply of 184 million coins emitted over 50 years. Wownero has no trusted setup, premine, or dev tax. Besides betting on online snail racing, the main use case of Wownero is micro-tipping meme creators with sound magic internet money. As a 100% community-driven, free and open source software, Wownero does not depend on billionaire shills or lame ass "influencers."
Unlike Opposing Projects.
Copyright (c) 2014-2023 The Monero Project.
Portions Copyright (c) 2012-2013 The Cryptonote developers.
## Resources
@ -16,35 +11,32 @@ Unlike Opposing Projects.
- Reddit: [/r/wownero](https://www.reddit.com/r/wownero)
- Mail: [wownero@wownero.org](mailto:wownero@wownero.org)
- Git: [git.wownero.com/wownero/wownero](https://git.wownero.com/wownero/wownero)
- Wownero Funding System: [funding.wownero.com](https://funding.wownero.com)
- Wownero Forum: [forum.wownero.com](https://forum.wownero.com)
- Discord: [discord.gg/ykZyAzJhDK](https://discord.com/invite/ykZyAzJhDK)
- Telegram: [t.me/wownero](https://t.me/wownero)
- Public Node Status: [monero.fail](https://monero.fail/?chain=wownero&network=mainnet)
- Wowlet Desktop Wallet: [git.wownero.com/wowlet/wowlet](https://git.wownero.com/wowlet/wowlet/releases)
- Stack Wallet iOS & Android Mobile Wallet: [stackwallet.com](https://stackwallet.com)
- Wonerujo Android Mobile Wallet: [google store](https://play.google.com/store/apps/details?id=com.m2049r.wowwallet)
- Elite Wallet Android Mobile Wallet: [github](https://github.com/Elite-Labs/EliteWallet)
- Public Node Status: [monero.fail](https://monero.fail/?crypto=wownero)
- Wownero Memes: [suchwow.xyz](https://suchwow.xyz/posts/top)
- Market Info: [coinmarketcap.com](https://coinmarketcap.com/currencies/wownero), [coingecko.com](https://www.coingecko.com/en/coins/wownero/usd)
## Exchanges
- [NonKYC](https://nonkyc.io/market/WOW_BTC)
- [neroswap](https://neroswap.com)
- [AltQuick](https://altquick.com/market/Wownero)
- [Majestic Bank](https://majesticbank.sc)
- [TradeOgre](https://tradeogre.com/exchange/BTC-WOW)
## Wallets
- Wonero CLI Wallet: [git.wownero.com/wownero/wownero](https://git.wownero.com/wownero/wownero/releases)
- Wowlet Desktop Wallet: [git.wownero.com/wowlet/wowlet](https://git.wownero.com/wowlet/wowlet/releases)
- Stack Wallet iOS & Android Mobile Wallet: [stackwallet.com](https://stackwallet.com)
- Wonerujo Android Mobile Wallet: [google store](https://play.google.com/store/apps/details?id=com.m2049r.wowwallet)
- Elite Wallet Android Mobile Wallet: [github](https://github.com/Elite-Labs/EliteWallet)
## Blockchain Explorers
### Blockchain Explorers
- https://explore.wownero.com
- https://explorer.suchwow.xyz
- https://kryfi.com/explorer/wownero
- https://muchwow.lol
## Introduction
Wownero is a privacy-centric memecoin that was fairly launched on April 1, 2018 with no pre-mine, stealth-mine or ICO. Wownero has a maximum supply of around 184 million WOW with a slow and steady emission over 50 years. It is a fork of Monero, but with its own genesis block, so there is no degradation of privacy due to ring signatures using different participants for the same tx outputs on opposing forks.
## Supporting the project
@ -57,7 +49,7 @@ height="100">](https://www.macstadium.com)
alt="JetBrains"
height="100">](https://www.jetbrains.com)
Developers are volunteers doing this mostly for shits and giggles. If you would like to support our shenanigans and stimulant addictions, please consider donating to the dev slush fund.
Developers are volunteers doing this mostly for shits and giggles. If you would like to support our shenanigans and stimulant addictions, please consider donating to [WFS proposals](https://funding.wownero.com/proposals) or the dev slush fund.
### Donation Addresses
@ -71,6 +63,12 @@ XMR: `44SQVPGLufPasUcuUQSZiF5c9BFzjcP8ucDxzzFDgLf1VkCEFaidJ3u2AhSKMhPLKA3jc2iS8w
BTC: `bc1qcw9zglp3fxyl25zswemw7jczlqryms2lsmu464`
### Open Collective
Open Collective is an online funding platform for open source software and collaborative communities. The platform brings together legal entities that act as a “Fiscal Host”, “Collectives” (unincorporated, community-based projects), and individuals interested in supporting projects with donations. Fiscal hosts hold donations for collectives in trust and handle all the taxes and legal stuff.
Wownero is hosted by Open Collective Europe, a Brussels-based non-profit that hosts many other collectives, such as Manjaro, EndeavourOS, Xfce, and peertube.social. If you would like donate to the Wownero Project using this method, you can check out our [Wownero - Open Collective](https://opencollective.com/wownero) page.
## Release staging and Contributing
**Anyone is welcome to contribute to Wownero's codebase!**
@ -98,7 +96,7 @@ Dates are provided in the format YYYY-MM-DD.
| - | 2020-06-28 | Hallucinogenic Hypnotoad | v0.8.0.0 | v0.8.0.2 | Dandelion++ support
| 253,999 | 2020-10-09 | Illiterate Illuminati | v0.9.0.0 | v0.9.3.3 | Dynamic coinbase unlock (up to 1 mo.), Deterministic unlock times, Enforce maximum coinbase amount, show_qr_code wallet command, CLSAG
| 331,170 | 2021-07-04 | Junkie Jeff | v0.10.0.0 | v0.10.2.0 | Bulletproofs+, Miner Block Header Signing, Vote by Block, Change coinbase unlock time to 1 day, Reset difficulty and switch back to Monero's difficulty algorithm
| 514,000 | 2023-04-01 | Kunty Karen | v0.11.0.0 | v0.11.2.0 | View tags, fee changes, adjusted dynamic block weight algorithm, multisig security fixes, RPC broadcast node donation sub-address, Limit tx_extra max size to ~1kb, 12-hour difficulty adjustment window
| 514,000 | 2023-04-01 | Kunty Karen | v0.11.0.0 | v0.11.1.0 | View tags, fee changes, adjusted dynamic block weight algorithm, multisig security fixes, RPC broadcast node donation sub-address, Limit tx_extra max size to ~1kb, 12-hour difficulty adjustment window
X's indicate that these details have not been determined as of commit date.
@ -217,6 +215,3 @@ More information on running Tor and i2p nodes is available [here](https://forum.
```
./wownero-wallet-cli --proxy 127.0.0.1:9050 --daemon-address iy6ry6uudpzvbd72zsipepukp6nsazjdu72n52vg3isfnxqn342flzad.onion:34568
```
Copyright (c) 2014-2024 The Monero Project.
Portions Copyright (c) 2012-2013 The Cryptonote developers.

@ -145,7 +145,7 @@ $(1)_build_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_stage_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_autoconf=./configure --host=$($($(1)_type)_host) --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)"
ifeq ($(filter $(1),libusb unbound),)
ifneq ($(1),libusb)
$(1)_autoconf += --disable-dependency-tracking
endif
ifneq ($($(1)_nm),)

@ -1,12 +1,12 @@
package=expat
$(package)_version=2.6.0
$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_$(subst .,_,$($(package)_version))/
$(package)_version=2.4.1
$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_4_1
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=ff60e6a6b6ce570ae012dc7b73169c7fdf4b6bf08c12ed0ec6f55736b78d85ba
$(package)_sha256_hash=2f9b6a580b94577b150a7d5617ad4643a4301a6616ff459307df3e225bcfbf40
define $(package)_set_vars
$(package)_config_opts=--disable-shared --without-docbook --without-tests --without-examples
$(package)_config_opts+=--enable-option-checking --without-xmlwf --with-pic
$(package)_config_opts=--enable-static
$(package)_config_opts=--disable-shared
$(package)_config_opts+=--prefix=$(host_prefix)
endef
@ -23,6 +23,6 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
rm -rf share lib/cmake lib/*.la
rm lib/*.la
endef

@ -1,8 +1,8 @@
package=openssl
$(package)_version=3.0.13
$(package)_version=3.0.11
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=88525753f79d3bec27d2fa7c66aa0b92b3aa9498dafd93d7cfa4b3780cdae313
$(package)_sha256_hash=b3425d3bb4a2218d0697eb41f7fc0cdede016ed19ca49d168b78e8d947887f55
define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"

@ -1,21 +1,18 @@
package=unbound
$(package)_version=1.19.1
$(package)_version=1.15.0
$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=bc1d576f3dd846a0739adc41ffaa702404c6767d2b6082deb9f2f97cbb24a3a9
$(package)_sha256_hash=a480dc6c8937447b98d161fe911ffc76cfaffa2da18788781314e81339f1126f
$(package)_dependencies=openssl expat
$(package)_patches=disable-glibc-reallocarray.patch
define $(package)_set_vars
$(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix)
$(package)_config_opts+=--with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no
$(package)_config_opts+=--without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only
$(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) --with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_w64=--enable-static-exe --sysconfdir=/etc --prefix=$(host_prefix) --target=$(host_prefix)
$(package)_config_opts_x86_64_darwin=ac_cv_func_SHA384_Init=yes
$(package)_build_opts_mingw32=LDFLAGS="$($(package)_ldflags) -lpthread"
$(package)_cflags_mingw32+="-D_WIN32_WINNT=0x600"
endef
define $(package)_preprocess_cmds
@ -34,3 +31,6 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
define $(package)_postprocess_cmds
endef

@ -144,11 +144,8 @@ elseif(ARCHITECTURE STREQUAL "aarch64")
endif()
if(ARCHITECTURE STREQUAL "riscv64")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(BUILD_TAG "linux-riscv64")
endif()
set(ARCH_ID "riscv64")
set(ARCH "rv64gc")
set(ARCH_ID "riscv64")
set(ARCH "rv64gc")
endif()
if(ARCHITECTURE STREQUAL "i686")

@ -245,8 +245,18 @@ namespace net_utils
}
}
// This magic var determines the maximum length for when copying the body message in
// memory is faster/more preferable than the round-trip time for one packet
constexpr size_t BODY_NO_COPY_CUTOFF = 128 * 1024; // ~262 KB or ~175 packets
// Maximum expected total headers bytes
constexpr size_t HEADER_RESERVE_SIZE = 2048;
const bool do_copy_body = body.size() <= BODY_NO_COPY_CUTOFF;
const size_t req_buff_cap = HEADER_RESERVE_SIZE + (do_copy_body ? body.size() : 0);
std::string req_buff{};
req_buff.reserve(2048);
req_buff.reserve(req_buff_cap);
req_buff.append(method.data(), method.size()).append(" ").append(uri.data(), uri.size()).append(" HTTP/1.1\r\n");
add_field(req_buff, "Host", m_host_buff);
add_field(req_buff, "Content-Length", std::to_string(body.size()));
@ -255,9 +265,7 @@ namespace net_utils
for(const auto& field : additional_params)
add_field(req_buff, field);
for (unsigned sends = 0; sends < 2; ++sends)
{
const std::size_t initial_size = req_buff.size();
const auto auth = m_auth.get_auth_field(method, uri);
if (auth)
add_field(req_buff, *auth);
@ -265,11 +273,21 @@ namespace net_utils
req_buff += "\r\n";
//--
bool res = m_net_client.send(req_buff, timeout);
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
if(body.size())
if (do_copy_body) // small body
{
// Copy headers + body together and potentially send one fewer packet
req_buff.append(body.data(), body.size());
const bool res = m_net_client.send(req_buff, timeout);
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
}
else // large body
{
// Send headers and body seperately to avoid copying heavy body message
bool res = m_net_client.send(req_buff, timeout);
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
res = m_net_client.send(body, timeout);
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND");
}
m_response_info.clear();
m_state = reciev_machine_state_header;
@ -282,19 +300,11 @@ namespace net_utils
return true;
}
switch (m_auth.handle_401(m_response_info))
if (m_auth.handle_401(m_response_info) == http_client_auth::kParseFailure)
{
case http_client_auth::kSuccess:
break;
case http_client_auth::kBadPassword:
sends = 2;
break;
default:
case http_client_auth::kParseFailure:
LOG_ERROR("Bad server response for authentication");
return false;
}
req_buff.resize(initial_size); // rollback for new auth generation
}
LOG_ERROR("Client has incorrect username/password for server requiring authentication");
return false;

@ -338,21 +338,11 @@ bool is_stdout_a_tty()
return is_a_tty.load(std::memory_order_relaxed);
}
static bool is_nocolor()
{
static const char *no_color_var = getenv("NO_COLOR");
static const bool no_color = no_color_var && *no_color_var; // apparently, NO_COLOR=0 means no color too (as per no-color.org)
return no_color;
}
void set_console_color(int color, bool bright)
{
if (!is_stdout_a_tty())
return;
if (is_nocolor())
return;
switch(color)
{
case console_color_default:
@ -471,9 +461,6 @@ void reset_console_color() {
if (!is_stdout_a_tty())
return;
if (is_nocolor())
return;
#ifdef WIN32
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);

@ -238,10 +238,6 @@ static char** attempted_completion(const char* text, int start, int end)
static void install_line_handler()
{
#if RL_READLINE_VERSION >= 0x0801
rl_variable_bind("enable-bracketed-paste", "off");
#endif
rl_attempted_completion_function = attempted_completion;
rl_callback_handler_install("", handle_line);
stifle_history(500);

@ -57,7 +57,7 @@ The dockrun.sh script will do everything to build the binaries. Just specify the
version to build as its only argument, e.g.
```bash
VERSION=v0.18.3.2
VERSION=v0.18.3.0
./dockrun.sh $VERSION
```

@ -133,7 +133,7 @@ Common setup part:
su - gitianuser
GH_USER=YOUR_GITHUB_USER_NAME
VERSION=v0.18.3.2
VERSION=v0.18.3.0
```
Where `GH_USER` is your GitHub user name and `VERSION` is the version tag you want to build.

@ -21,7 +21,6 @@ packages:
- "g++-7-arm-linux-gnueabihf"
- "gcc-arm-linux-gnueabihf"
- "g++-arm-linux-gnueabihf"
- "g++-riscv64-linux-gnu"
- "g++-7-multilib"
- "gcc-7-multilib"
- "binutils-arm-linux-gnueabihf"
@ -44,7 +43,7 @@ files: []
script: |
WRAP_DIR=$HOME/wrapped
HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu i686-linux-gnu riscv64-linux-gnu"
HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu i686-linux-gnu"
FAKETIME_HOST_PROGS=""
FAKETIME_PROGS="date"
HOST_CFLAGS="-O2 -g"
@ -160,13 +159,7 @@ script: |
fi
export C_INCLUDE_PATH="$EXTRA_INCLUDES"
export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES"
# glibc only added riscv support in 2.27, disable backwards compatibility
if [ "$i" == "riscv64-linux-gnu" ]; then
BACKCOMPAT_OPTION=OFF
else
BACKCOMPAT_OPTION=ON
fi
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=${BACKCOMPAT_OPTION} -DCMAKE_SKIP_RPATH=ON
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=ON -DCMAKE_SKIP_RPATH=ON
make ${MAKEOPTS}
chmod 755 bin/*
cp ../utils/conf/wow.conf bin

@ -71,13 +71,13 @@ type, and max connections:
```
--anonymous-inbound rveahdfho7wo4b2m.onion:28083,127.0.0.1:28083,25
--anonymous-inbound cmeua5767mz2q5jsaelk2rxhf67agrwuetaso5dzbenyzwlbkg2q.b32.i2p,127.0.0.1:30000
--anonymous-inbound cmeua5767mz2q5jsaelk2rxhf67agrwuetaso5dzbenyzwlbkg2q.b32.i2p:5000,127.0.0.1:30000
```
which tells `monerod` that a max of 25 inbound Tor connections are being
received at address "rveahdfho7wo4b2m.onion:28083" and forwarded to `monerod`
localhost port 28083, and a default max I2P connections are being received at
address "cmeua5767mz2q5jsaelk2rxhf67agrwuetaso5dzbenyzwlbkg2q.b32.i2p" and
address "cmeua5767mz2q5jsaelk2rxhf67agrwuetaso5dzbenyzwlbkg2q.b32.i2p:5000" and
forwarded to `monerod` localhost port 30000.
These addresses will be shared with outgoing peers, over the same network type,
otherwise the peer will not be notified of the peer address by the proxy.

@ -149,11 +149,6 @@ static el::Color colorFromLevel(el::Level level)
static void setConsoleColor(el::Color color, bool bright)
{
static const char *no_color_var = getenv("NO_COLOR");
static const bool no_color = no_color_var && *no_color_var; // apparently, NO_COLOR=0 means no color too (as per no-color.org)
if (no_color)
return;
#if ELPP_OS_WINDOWS
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
switch (color)

@ -52,9 +52,11 @@ using namespace cryptonote;
static std::string db_path;
// default to fast:1
static uint64_t records_per_sync = 128;
static uint64_t records_per_sync = 16 * 65536;
static const size_t slack = 512 * 1024 * 1024;
static std::vector<bool> is_v1;
static std::error_code replace_file(const boost::filesystem::path& replacement_name, const boost::filesystem::path& replaced_name)
{
std::error_code ec = tools::replace_file(replacement_name.string(), replaced_name.string());
@ -89,6 +91,14 @@ static void close(MDB_env *env)
mdb_env_close(env);
}
static void mark_v1_tx(const MDB_val &k, const MDB_val &v)
{
const uint64_t tx_id = *(const uint64_t*)k.mv_data;
if (tx_id >= is_v1.size())
is_v1.resize(tx_id + 1, false);
is_v1[tx_id] = cryptonote::is_v1_tx(cryptonote::blobdata_ref{(const char*)v.mv_data, v.mv_size});
}
static void add_size(MDB_env *env, uint64_t bytes)
{
try
@ -136,7 +146,7 @@ static void check_resize(MDB_env *env, size_t bytes)
add_size(env, size_used + bytes + 2 * slack - mei.me_mapsize);
}
static bool resize_point(size_t nrecords, MDB_env *env, MDB_txn **txn, size_t &bytes)
static bool resize_point(size_t &nrecords, MDB_env *env, MDB_txn **txn, size_t &bytes)
{
if (nrecords % records_per_sync && bytes <= slack / 2)
return false;
@ -146,10 +156,11 @@ static bool resize_point(size_t nrecords, MDB_env *env, MDB_txn **txn, size_t &b
dbr = mdb_txn_begin(env, NULL, 0, txn);
if (dbr) throw std::runtime_error("Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr)));
bytes = 0;
nrecords = 0;
return true;
}
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)
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;
MDB_txn *txn0, *txn1;
@ -200,6 +211,11 @@ static void copy_table(MDB_env *env0, MDB_env *env1, const char *table, unsigned
dbr = mdb_cursor_open(txn1, dbi1, &cur1);
if (dbr) throw std::runtime_error("Failed to create LMDB cursor: " + std::string(mdb_strerror(dbr)));
if (flags & MDB_DUPSORT)
putflags |= MDB_APPENDDUP;
else
putflags |= MDB_APPEND;
MDB_val k;
MDB_val v;
MDB_cursor_op op = MDB_FIRST;
@ -214,7 +230,8 @@ static void copy_table(MDB_env *env0, MDB_env *env1, const char *table, unsigned
throw std::runtime_error("Failed to enumerate " + std::string(table) + " records: " + std::string(mdb_strerror(ret)));
bytes += k.mv_size + v.mv_size;
if (resize_point(++nrecords, env1, &txn1, bytes))
++nrecords;
if (resize_point(nrecords, env1, &txn1, bytes))
{
dbr = mdb_cursor_open(txn1, dbi1, &cur1);
if (dbr) throw std::runtime_error("Failed to create LMDB cursor: " + std::string(mdb_strerror(dbr)));
@ -223,6 +240,9 @@ static void copy_table(MDB_env *env0, MDB_env *env1, const char *table, unsigned
ret = mdb_cursor_put(cur1, &k, &v, putflags);
if (ret)
throw std::runtime_error("Failed to write " + std::string(table) + " record: " + std::string(mdb_strerror(ret)));
if (f)
(*f)(k, v);
}
mdb_cursor_close(cur1);
@ -235,17 +255,6 @@ static void copy_table(MDB_env *env0, MDB_env *env1, const char *table, unsigned
mdb_dbi_close(env0, dbi0);
}
static bool is_v1_tx(MDB_cursor *c_txs_pruned, MDB_val *tx_id)
{
MDB_val v;
int ret = mdb_cursor_get(c_txs_pruned, tx_id, &v, MDB_SET);
if (ret)
throw std::runtime_error("Failed to find transaction pruned data: " + std::string(mdb_strerror(ret)));
if (v.mv_size == 0)
throw std::runtime_error("Invalid transaction pruned data");
return cryptonote::is_v1_tx(cryptonote::blobdata_ref{(const char*)v.mv_data, v.mv_size});
}
static void prune(MDB_env *env0, MDB_env *env1)
{
MDB_dbi dbi0_blocks, dbi0_txs_pruned, dbi0_txs_prunable, dbi0_tx_indices, dbi1_txs_prunable, dbi1_txs_prunable_tip, dbi1_properties;
@ -324,7 +333,10 @@ static void prune(MDB_env *env0, MDB_env *env1)
mdb_dbi_close(env0, dbi0_blocks);
const uint64_t blockchain_height = stats.ms_entries;
size_t nrecords = 0, bytes = 0;
std::vector<bool> prunable_needed;
// go through all txes tx indices, recording which ones should have their prunable part retained
MINFO("Marking prunable txes");
MDB_cursor_op op = MDB_FIRST;
while (1)
{
@ -336,7 +348,8 @@ static void prune(MDB_env *env0, MDB_env *env1)
const txindex *ti = (const txindex*)v.mv_data;
const uint64_t block_height = ti->data.block_id;
MDB_val_set(kk, ti->data.tx_id);
const uint64_t tx_id = ti->data.tx_id;
MDB_val_set(kk, tx_id);
if (block_height + CRYPTONOTE_PRUNING_TIP_BLOCKS >= blockchain_height)
{
MDEBUG(block_height << "/" << blockchain_height << " is in tip");
@ -344,22 +357,23 @@ static void prune(MDB_env *env0, MDB_env *env1)
dbr = mdb_cursor_put(cur1_txs_prunable_tip, &kk, &vv, 0);
if (dbr) throw std::runtime_error("Failed to write prunable tx tip data: " + std::string(mdb_strerror(dbr)));
bytes += kk.mv_size + vv.mv_size;
}
if (tools::has_unpruned_block(block_height, blockchain_height, pruning_seed) || is_v1_tx(cur0_txs_pruned, &kk))
{
MDB_val vv;
dbr = mdb_cursor_get(cur0_txs_prunable, &kk, &vv, MDB_SET);
if (dbr) throw std::runtime_error("Failed to read prunable tx data: " + std::string(mdb_strerror(dbr)));
bytes += kk.mv_size + vv.mv_size;
if (resize_point(++nrecords, env1, &txn1, bytes))
++nrecords;
if (resize_point(nrecords, env1, &txn1, bytes))
{
dbr = mdb_cursor_open(txn1, dbi1_txs_prunable, &cur1_txs_prunable);
if (dbr) throw std::runtime_error("Failed to create LMDB cursor: " + std::string(mdb_strerror(dbr)));
dbr = mdb_cursor_open(txn1, dbi1_txs_prunable_tip, &cur1_txs_prunable_tip);
if (dbr) throw std::runtime_error("Failed to create LMDB cursor: " + std::string(mdb_strerror(dbr)));
}
dbr = mdb_cursor_put(cur1_txs_prunable, &kk, &vv, 0);
if (dbr) throw std::runtime_error("Failed to write prunable tx data: " + std::string(mdb_strerror(dbr)));
}
if (tx_id >= is_v1.size())
throw std::runtime_error("tx_id out of range of is_v1 vector");
if (tools::has_unpruned_block(block_height, blockchain_height, pruning_seed) || is_v1[tx_id])
{
if (tx_id >= prunable_needed.size())
prunable_needed.resize(tx_id + 1, false);
prunable_needed[tx_id] = true;
}
else
{
@ -367,6 +381,37 @@ static void prune(MDB_env *env0, MDB_env *env1)
}
}
// go through prunable parts, carrying over those we need
MINFO("Copying retained prunable data");
op = MDB_FIRST;
while (1)
{
int ret = mdb_cursor_get(cur0_txs_prunable, &k, &v, op);
op = MDB_NEXT;
if (ret == MDB_NOTFOUND)
break;
if (ret) throw std::runtime_error("Failed to enumerate records: " + std::string(mdb_strerror(ret)));
const uint64_t tx_id = *(const uint64_t*)k.mv_data;
if (tx_id >= prunable_needed.size())
throw std::runtime_error("tx_id out of range of prunable_needed vector");
if (prunable_needed[tx_id])
{
dbr = mdb_cursor_put(cur1_txs_prunable, &k, &v, MDB_APPEND);
if (dbr) throw std::runtime_error("Failed to write prunable tx data: " + std::string(mdb_strerror(dbr)));
bytes += k.mv_size + v.mv_size;
++nrecords;
if (resize_point(nrecords, env1, &txn1, bytes))
{
dbr = mdb_cursor_open(txn1, dbi1_txs_prunable, &cur1_txs_prunable);
if (dbr) throw std::runtime_error("Failed to create LMDB cursor: " + std::string(mdb_strerror(dbr)));
dbr = mdb_cursor_open(txn1, dbi1_txs_prunable_tip, &cur1_txs_prunable_tip);
if (dbr) throw std::runtime_error("Failed to create LMDB cursor: " + std::string(mdb_strerror(dbr)));
}
}
}
mdb_cursor_close(cur1_txs_prunable_tip);
mdb_cursor_close(cur1_txs_prunable);
mdb_cursor_close(cur0_txs_prunable);
@ -419,7 +464,7 @@ static bool parse_db_sync_mode(std::string db_sync_mode, uint64_t &db_flags)
else if(options[0] == "fastest")
{
db_flags = DBF_FASTEST;
records_per_sync = 1000; // default to fastest:async:1000
// default to fastest:async:N
}
else
return false;
@ -455,7 +500,7 @@ int main(int argc, char* argv[])
const command_line::arg_descriptor<std::string> arg_db_sync_mode = {
"db-sync-mode"
, "Specify sync option, using format [safe|fast|fastest]:[nrecords_per_sync]."
, "fast:1000"
, "fast:" + std::to_string(records_per_sync)
};
const command_line::arg_descriptor<bool> arg_copy_pruned_database = {"copy-pruned-database", "Copy database anyway if already pruned"};
@ -601,26 +646,27 @@ int main(int argc, char* argv[])
MDB_env *env0 = NULL, *env1 = NULL;
open(env0, paths[0], db_flags, true);
open(env1, paths[1], db_flags, false);
copy_table(env0, env1, "blocks", MDB_INTEGERKEY, MDB_APPEND);
copy_table(env0, env1, "block_info", MDB_INTEGERKEY | MDB_DUPSORT| MDB_DUPFIXED, MDB_APPENDDUP, BlockchainLMDB::compare_uint64);
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);
//copy_table(env0, env1, "txs", MDB_INTEGERKEY);
copy_table(env0, env1, "txs_pruned", MDB_INTEGERKEY, MDB_APPEND);
copy_table(env0, env1, "txs_prunable_hash", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_APPEND);
copy_table(env0, env1, "txs_pruned", MDB_INTEGERKEY, 0, NULL, &mark_v1_tx);
copy_table(env0, env1, "txs_prunable_hash", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, 0);
// not copied: prunable, prunable_tip
copy_table(env0, env1, "tx_indices", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, 0, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "tx_outputs", MDB_INTEGERKEY, MDB_APPEND);
copy_table(env0, env1, "output_txs", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_APPENDDUP, BlockchainLMDB::compare_uint64);
copy_table(env0, env1, "output_amounts", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_APPENDDUP, BlockchainLMDB::compare_uint64);
copy_table(env0, env1, "spent_keys", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_NODUPDATA, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "txpool_meta", 0, MDB_NODUPDATA, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "txpool_blob", 0, MDB_NODUPDATA, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "hf_versions", MDB_INTEGERKEY, MDB_APPEND);
copy_table(env0, env1, "tx_outputs", MDB_INTEGERKEY, 0);
copy_table(env0, env1, "output_txs", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, 0, BlockchainLMDB::compare_uint64);
copy_table(env0, env1, "output_amounts", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, 0, BlockchainLMDB::compare_uint64);
copy_table(env0, env1, "spent_keys", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, 0, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "txpool_meta", 0, 0, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "txpool_blob", 0, 0, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "alt_blocks", 0, 0, BlockchainLMDB::compare_hash32);
copy_table(env0, env1, "hf_versions", MDB_INTEGERKEY, 0);
copy_table(env0, env1, "properties", 0, 0, BlockchainLMDB::compare_string);
if (already_pruned)
{
copy_table(env0, env1, "txs_prunable", MDB_INTEGERKEY, MDB_APPEND, BlockchainLMDB::compare_uint64);
copy_table(env0, env1, "txs_prunable_tip", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, MDB_NODUPDATA, BlockchainLMDB::compare_uint64);
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
{

Binary file not shown.

@ -240,7 +240,6 @@ namespace cryptonote
ADD_CHECKPOINT2(516700, "0443c47c5a4e344c3f68a491a3b2f6b78a769cdf9076249c93f187ececf9cc7c", "0x12128a532a59a6");
ADD_CHECKPOINT2(522000, "8c15ae514063bf05e7662ab33b86a4131aa89df0784ce3da7876c5339bc1de3d", "0x123d9c604a7be6");
ADD_CHECKPOINT2(566000, "136e37f5f130dd2dc2d8d30e46e16d74377cb834b7c5be32cd09ee6ad402556c", "0x1318d703b1bff7");
ADD_CHECKPOINT2(611300, "34fd2ff914ad34edc2dabb0fe38f15b2ac6a301dc501bdfec15d2108b304a455", "0x13b61f061add9d");
return true;
}

@ -34,7 +34,7 @@ typedef struct {
unsigned long long databitlen; /*the message size in bits*/
unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/
DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/
DATA_ALIGN16(unsigned char buffer[64]); /*the 512-bit message block to be hashed;*/
unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/
} hashState;
@ -213,24 +213,16 @@ static void E8(hashState *state)
/*The compression function F8 */
static void F8(hashState *state)
{
uint64_t* x = (uint64_t*)state->x;
uint64 i;
/*xor the 512-bit message with the fist half of the 1024-bit hash state*/
for (int i = 0; i < 8; ++i) {
uint64 b;
memcpy(&b, &state->buffer[i << 3], sizeof(b));
x[i] ^= b;
}
for (i = 0; i < 8; i++) state->x[i >> 1][i & 1] ^= ((uint64*)state->buffer)[i];
/*the bijective function E8 */
E8(state);
/*xor the 512-bit message with the second half of the 1024-bit hash state*/
for (int i = 0; i < 8; ++i) {
uint64 b;
memcpy(&b, &state->buffer[i << 3], sizeof(b));
x[i + 8] ^= b;
}
for (i = 0; i < 8; i++) state->x[(8+i) >> 1][(8+i) & 1] ^= ((uint64*)state->buffer)[i];
}
/*before hashing a message, initialize the hash state as H0 */
@ -248,7 +240,6 @@ static HashReturn Init(hashState *state, int hashbitlen)
case 224: memcpy(state->x,JH224_H0,128); break;
case 256: memcpy(state->x,JH256_H0,128); break;
case 384: memcpy(state->x,JH384_H0,128); break;
default:
case 512: memcpy(state->x,JH512_H0,128); break;
}

@ -52,7 +52,7 @@ namespace cryptonote
// load
template <template <bool> class Archive>
bool member_do_serialize(Archive<false>& ar)
bool do_serialize(Archive<false>& ar)
{
// size - 1 - because of variant tag
for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size)
@ -73,7 +73,7 @@ namespace cryptonote
// store
template <template <bool> class Archive>
bool member_do_serialize(Archive<true>& ar)
bool do_serialize(Archive<true>& ar)
{
if(TX_EXTRA_PADDING_MAX_COUNT < size)
return false;
@ -129,7 +129,7 @@ namespace cryptonote
// load
template <template <bool> class Archive>
bool member_do_serialize(Archive<false>& ar)
bool do_serialize(Archive<false>& ar)
{
std::string field;
if(!::do_serialize(ar, field))
@ -142,7 +142,7 @@ namespace cryptonote
// store
template <template <bool> class Archive>
bool member_do_serialize(Archive<true>& ar)
bool do_serialize(Archive<true>& ar)
{
std::ostringstream oss;
binary_archive<true> oar(oss);

@ -30,7 +30,6 @@
#pragma once
#include <cstdint>
#include <stdexcept>
#include <string>
#include <boost/uuid/uuid.hpp>

@ -3945,8 +3945,6 @@ void Blockchain::get_dynamic_base_fee_estimate_2021_scaling(uint64_t grace_block
const uint8_t version = get_current_hard_fork_version();
const uint64_t db_height = m_db->height();
CHECK_AND_ASSERT_THROW_MES(grace_blocks <= CRYPTONOTE_REWARD_BLOCKS_WINDOW, "Grace blocks invalid In 2021 fee scaling estimate.");
// we want Mlw = median of max((min(Mbw, 1.7 * Ml), Zm), Ml / 1.7)
// Mbw: block weight for the last 99990 blocks, 0 for the next 10
// Ml: penalty free zone (dynamic), aka long_term_median, aka median of max((min(Mb, 1.7 * Ml), Zm), Ml / 1.7)
@ -3960,6 +3958,7 @@ void Blockchain::get_dynamic_base_fee_estimate_2021_scaling(uint64_t grace_block
const uint64_t Mlw_penalty_free_zone_for_wallet = std::max<uint64_t>(rm.median(), CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5);
// Msw: median over [100 - grace blocks] past + [grace blocks] future blocks
CHECK_AND_ASSERT_THROW_MES(grace_blocks <= 100, "Grace blocks invalid In 2021 fee scaling estimate.");
std::vector<uint64_t> weights;
get_last_n_blocks_weights(weights, 100 - grace_blocks);
weights.reserve(100);
@ -5672,7 +5671,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "3c0d098139491ab668f9f063747e31a3f3b09fa519ab68f90026da8641dfc913";
static const char expected_block_hashes_hash[] = "9ce2e9f40ff58954d6176e300af1d8da1804b829e1be8565805fea497df40f4b";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)

@ -247,7 +247,6 @@ namespace cryptonote
LOG_PRINT_L1("Transaction with id= "<< id << " used already spent key images");
tvc.m_verifivation_failed = true;
tvc.m_double_spend = true;
tvc.m_no_drop_offense = true;
return false;
}
}
@ -436,14 +435,8 @@ namespace cryptonote
void tx_memory_pool::prune(size_t bytes)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
// Nothing to do if already empty
if (m_txs_by_fee_and_receive_time.empty())
return;
if (bytes == 0)
bytes = m_txpool_max_weight;
CRITICAL_REGION_LOCAL1(m_blockchain);
LockedTXN lock(m_blockchain.get_db());
bool changed = false;
@ -488,13 +481,8 @@ namespace cryptonote
reduce_txpool_weight(meta.weight);
remove_transaction_keyimages(tx, txid);
MINFO("Pruned tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first);
auto it_prev = it;
--it_prev;
remove_tx_from_transient_lists(it, txid, !meta.matches(relay_category::broadcasted));
it = it_prev;
it--;
changed = true;
}
catch (const std::exception &e)
@ -1086,7 +1074,7 @@ namespace cryptonote
// If the total weight is too high, choose the best paying transactions
if (total_weight > max_backlog_weight)
std::stable_sort(tmp.begin(), tmp.end(), [](const auto& a, const auto& b){ return a.fee * b.weight > b.fee * a.weight; });
std::sort(tmp.begin(), tmp.end(), [](const auto& a, const auto& b){ return a.fee * b.weight > b.fee * a.weight; });
backlog.clear();
uint64_t w = 0;
@ -1839,7 +1827,7 @@ namespace cryptonote
auto sorted_it = find_tx_in_sorted_container(txid);
if (sorted_it == m_txs_by_fee_and_receive_time.end())
{
MDEBUG("Re-adding tx " << txid << " to tx pool, but it was not found in the sorted txs container");
MERROR("Re-adding tx " << txid << " to tx pool, but it was not found in the sorted txs container");
}
else
{

@ -69,12 +69,11 @@ namespace cryptonote
{
// sort by greatest first, not least
if (a.first.first > b.first.first) return true;
if (a.first.first < b.first.first) return false;
if (a.first.second < b.first.second) return true;
if (a.first.second > b.first.second) return false;
return memcmp(a.second.data, b.second.data, sizeof(crypto::hash)) < 0;
else if (a.first.first < b.first.first) return false;
else if (a.first.second < b.first.second) return true;
else if (a.first.second > b.first.second) return false;
else if (a.second != b.second) return true;
else return false;
}
};

@ -206,13 +206,8 @@ namespace multisig
//----------------------------------------------------------------------------------------------------------------------
void multisig_kex_msg::parse_and_validate_msg()
{
CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() == MULTISIG_KEX_MSG_V2_MAGIC_N.size(),
"Multisig kex msg magic inconsistency.");
CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() >= MULTISIG_KEX_V1_MAGIC.size(),
"Multisig kex msg magic inconsistency.");
// check message type
CHECK_AND_ASSERT_THROW_MES(m_msg.size() >= MULTISIG_KEX_MSG_V2_MAGIC_1.size(), "Kex message unexpectedly small.");
CHECK_AND_ASSERT_THROW_MES(m_msg.size() > 0, "Kex message unexpectedly empty.");
CHECK_AND_ASSERT_THROW_MES(m_msg.substr(0, MULTISIG_KEX_V1_MAGIC.size()) != MULTISIG_KEX_V1_MAGIC,
"V1 multisig kex messages are deprecated (unsafe).");
CHECK_AND_ASSERT_THROW_MES(m_msg.substr(0, MULTISIG_KEX_MSG_V1_MAGIC.size()) != MULTISIG_KEX_MSG_V1_MAGIC,
@ -220,6 +215,8 @@ namespace multisig
// deserialize the message
std::string msg_no_magic;
CHECK_AND_ASSERT_THROW_MES(MULTISIG_KEX_MSG_V2_MAGIC_1.size() == MULTISIG_KEX_MSG_V2_MAGIC_N.size(),
"Multisig kex msg magic inconsistency.");
CHECK_AND_ASSERT_THROW_MES(tools::base58::decode(m_msg.substr(MULTISIG_KEX_MSG_V2_MAGIC_1.size()), msg_no_magic),
"Multisig kex msg decoding error.");
binary_archive<false> b_archive{epee::strspan<std::uint8_t>(msg_no_magic)};

@ -71,7 +71,7 @@ namespace net
struct i2p_serialized
{
std::string host;
std::uint16_t port; //! Leave for compatability with older clients
std::uint16_t port;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(host)
@ -80,7 +80,8 @@ namespace net
};
}
i2p_address::i2p_address(const boost::string_ref host) noexcept
i2p_address::i2p_address(const boost::string_ref host, const std::uint16_t port) noexcept
: port_(port)
{
// this is a private constructor, throw if moved to public
assert(host.size() < sizeof(host_));
@ -96,19 +97,27 @@ namespace net
}
i2p_address::i2p_address() noexcept
: port_(0)
{
static_assert(sizeof(unknown_host) <= sizeof(host_), "bad buffer size");
std::memcpy(host_, unknown_host, sizeof(unknown_host));
std::memset(host_ + sizeof(unknown_host), 0, sizeof(host_) - sizeof(unknown_host));
}
expect<i2p_address> i2p_address::make(const boost::string_ref address)
expect<i2p_address> i2p_address::make(const boost::string_ref address, const std::uint16_t default_port)
{
boost::string_ref host = address.substr(0, address.rfind(':'));
const boost::string_ref port =
address.substr(host.size() + (host.size() == address.size() ? 0 : 1));
MONERO_CHECK(host_check(host));
std::uint16_t porti = default_port;
if (!port.empty() && !epee::string_tools::get_xtype_from_string(porti, std::string{port}))
return {net::error::invalid_port};
static_assert(b32_length + sizeof(tld) == sizeof(i2p_address::host_), "bad internal host size");
return i2p_address{host};
return i2p_address{host, porti};
}
bool i2p_address::_load(epee::serialization::portable_storage& src, epee::serialization::section* hparent)
@ -118,21 +127,23 @@ namespace net
{
std::memcpy(host_, in.host.data(), in.host.size());
std::memset(host_ + in.host.size(), 0, sizeof(host_) - in.host.size());
port_ = in.port;
return true;
}
static_assert(sizeof(unknown_host) <= sizeof(host_), "bad buffer size");
std::memcpy(host_, unknown_host, sizeof(unknown_host)); // include null terminator
port_ = 0;
return false;
}
bool i2p_address::store(epee::serialization::portable_storage& dest, epee::serialization::section* hparent) const
{
// Set port to 1 for backwards compatability; zero is invalid port
const i2p_serialized out{std::string{host_}, 1};
const i2p_serialized out{std::string{host_}, port_};
return out.store(dest, hparent);
}
i2p_address::i2p_address(const i2p_address& rhs) noexcept
: port_(rhs.port_)
{
std::memcpy(host_, rhs.host_, sizeof(host_));
}
@ -141,6 +152,7 @@ namespace net
{
if (this != std::addressof(rhs))
{
port_ = rhs.port_;
std::memcpy(host_, rhs.host_, sizeof(host_));
}
return *this;
@ -154,12 +166,13 @@ namespace net
bool i2p_address::equal(const i2p_address& rhs) const noexcept
{
return is_same_host(rhs);
return port_ == rhs.port_ && is_same_host(rhs);
}
bool i2p_address::less(const i2p_address& rhs) const noexcept
{
return std::strcmp(host_str(), rhs.host_str()) < 0;
int res = std::strcmp(host_str(), rhs.host_str());
return res < 0 || (res == 0 && port() < rhs.port());
}
bool i2p_address::is_same_host(const i2p_address& rhs) const noexcept
@ -169,6 +182,20 @@ namespace net
std::string i2p_address::str() const
{
return host_str();
const std::size_t host_length = std::strlen(host_str());
const std::size_t port_length =
port_ == 0 ? 0 : std::numeric_limits<std::uint16_t>::digits10 + 2;
std::string out{};
out.reserve(host_length + port_length);
out.assign(host_str(), host_length);
if (port_ != 0)
{
out.push_back(':');
namespace karma = boost::spirit::karma;
karma::generate(std::back_inserter(out), karma::ushort_, port());
}
return out;
}
}

@ -50,10 +50,11 @@ namespace net
//! b32 i2p address; internal format not condensed/decoded.
class i2p_address
{
std::uint16_t port_;
char host_[61]; // null-terminated
//! Keep in private, `host.size()` has no runtime check
i2p_address(boost::string_ref host) noexcept;
i2p_address(boost::string_ref host, std::uint16_t port) noexcept;
public:
//! \return Size of internal buffer for host.
@ -73,7 +74,7 @@ namespace net
with `default_port` being used if port is not specified in
`address`.
*/
static expect<i2p_address> make(boost::string_ref address);
static expect<i2p_address> make(boost::string_ref address, std::uint16_t default_port = 0);
//! Load from epee p2p format, and \return false if not valid tor address
bool _load(epee::serialization::portable_storage& src, epee::serialization::section* hparent);
@ -102,8 +103,8 @@ namespace net
//! \return Null-terminated `x.b32.i2p` value or `unknown_str()`.
const char* host_str() const noexcept { return host_; }
//! \return `1` to work with I2P socks which considers `0` error.
std::uint16_t port() const noexcept { return 1; }
//! \return Port value or `0` if unspecified.
std::uint16_t port() const noexcept { return port_; }
static constexpr bool is_loopback() noexcept { return false; }
static constexpr bool is_local() noexcept { return false; }

@ -81,7 +81,7 @@ namespace net
if (host_str_ref.ends_with(".onion"))
return tor_address::make(address, default_port);
if (host_str_ref.ends_with(".i2p"))
return i2p_address::make(address);
return i2p_address::make(address, default_port);
boost::system::error_code ec;
boost::asio::ip::address_v6 v6 = boost::asio::ip::address_v6::from_string(host_str, ec);

@ -196,7 +196,7 @@ namespace boost
if (std::strcmp(host, net::i2p_address::unknown_str()) == 0)
na = net::i2p_address::unknown();
else
na = MONERO_UNWRAP(net::i2p_address::make(host));
na = MONERO_UNWRAP(net::i2p_address::make(host, port));
}
template <class Archive, class ver_type>

@ -329,10 +329,6 @@ namespace rct {
ctkeyV outPk;
xmr_amount txnFee; // contains b
rctSigBase() :
type(RCTTypeNull), message{}, mixRing{}, pseudoOuts{}, ecdhInfo{}, outPk{}, txnFee(0)
{}
template<bool W, template <bool> class Archive>
bool serialize_rctsig_base(Archive<W> &ar, size_t inputs, size_t outputs)
{
@ -370,17 +366,11 @@ namespace rct {
{
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus)
{
// Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
// first 8 bytes of ecdhInfo[i].amount
ar.begin_object();
crypto::hash8 trunc_amount; // placeholder variable needed to maintain "strict aliasing"
if (!typename Archive<W>::is_saving()) // loading
if (!typename Archive<W>::is_saving())
memset(ecdhInfo[i].amount.bytes, 0, sizeof(ecdhInfo[i].amount.bytes));
else // saving
memcpy(trunc_amount.data, ecdhInfo[i].amount.bytes, sizeof(trunc_amount));
FIELD_N("amount", trunc_amount);
if (!typename Archive<W>::is_saving()) // loading
memcpy(ecdhInfo[i].amount.bytes, trunc_amount.data, sizeof(trunc_amount));
crypto::hash8 &amount = (crypto::hash8&)ecdhInfo[i].amount;
FIELD(amount);
ar.end_object();
}
else

@ -48,11 +48,6 @@ void GetHeight::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) c
void GetHeight::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, height, height);
}
@ -66,11 +61,6 @@ void GetBlocksFast::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void GetBlocksFast::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, block_ids, block_ids);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, prune, prune);
@ -86,11 +76,6 @@ void GetBlocksFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
void GetBlocksFast::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, blocks, blocks);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, current_height, current_height);
@ -106,11 +91,6 @@ void GetHashesFast::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void GetHashesFast::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, known_hashes, known_hashes);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
}
@ -120,16 +100,10 @@ void GetHashesFast::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
INSERT_INTO_JSON_OBJECT(dest, hashes, hashes);
INSERT_INTO_JSON_OBJECT(dest, start_height, start_height);
INSERT_INTO_JSON_OBJECT(dest, current_height, current_height);
}
void GetHashesFast::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, hashes, hashes);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, current_height, current_height);
@ -143,11 +117,6 @@ void GetTransactions::Request::doToJson(rapidjson::Writer<epee::byte_stream>& de
void GetTransactions::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, tx_hashes, tx_hashes);
}
@ -159,11 +128,6 @@ void GetTransactions::Response::doToJson(rapidjson::Writer<epee::byte_stream>& d
void GetTransactions::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, txs, txs);
GET_FROM_JSON_OBJECT(val, missed_hashes, missed_hashes);
}
@ -176,11 +140,6 @@ void KeyImagesSpent::Request::doToJson(rapidjson::Writer<epee::byte_stream>& des
void KeyImagesSpent::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, key_images, key_images);
}
@ -191,11 +150,6 @@ void KeyImagesSpent::Response::doToJson(rapidjson::Writer<epee::byte_stream>& de
void KeyImagesSpent::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, spent_status, spent_status);
}
@ -207,11 +161,6 @@ void GetTxGlobalOutputIndices::Request::doToJson(rapidjson::Writer<epee::byte_st
void GetTxGlobalOutputIndices::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, tx_hash, tx_hash);
}
@ -222,11 +171,6 @@ void GetTxGlobalOutputIndices::Response::doToJson(rapidjson::Writer<epee::byte_s
void GetTxGlobalOutputIndices::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
}
@ -238,11 +182,6 @@ void SendRawTx::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest) co
void SendRawTx::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, tx, tx);
GET_FROM_JSON_OBJECT(val, relay, relay);
}
@ -255,11 +194,6 @@ void SendRawTx::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) c
void SendRawTx::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, relayed, relayed);
}
@ -271,11 +205,6 @@ void SendRawTxHex::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void SendRawTxHex::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, tx_as_hex, tx_as_hex);
GET_FROM_JSON_OBJECT(val, relay, relay);
}
@ -290,11 +219,6 @@ void StartMining::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void StartMining::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, miner_address, miner_address);
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
GET_FROM_JSON_OBJECT(val, do_background_mining, do_background_mining);
@ -342,11 +266,6 @@ void MiningStatus::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void MiningStatus::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, active, active);
GET_FROM_JSON_OBJECT(val, speed, speed);
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
@ -369,11 +288,6 @@ void GetInfo::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest) con
void GetInfo::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, info, info);
}
@ -400,11 +314,6 @@ void GetBlockHash::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void GetBlockHash::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, height, height);
}
@ -415,11 +324,6 @@ void GetBlockHash::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void GetBlockHash::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, hash, hash);
}
@ -438,11 +342,6 @@ void GetLastBlockHeader::Response::doToJson(rapidjson::Writer<epee::byte_stream>
void GetLastBlockHeader::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, header, header);
}
@ -454,11 +353,6 @@ void GetBlockHeaderByHash::Request::doToJson(rapidjson::Writer<epee::byte_stream
void GetBlockHeaderByHash::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, hash, hash);
}
@ -469,11 +363,6 @@ void GetBlockHeaderByHash::Response::doToJson(rapidjson::Writer<epee::byte_strea
void GetBlockHeaderByHash::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, header, header);
}
@ -485,11 +374,6 @@ void GetBlockHeaderByHeight::Request::doToJson(rapidjson::Writer<epee::byte_stre
void GetBlockHeaderByHeight::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, height, height);
}
@ -500,11 +384,6 @@ void GetBlockHeaderByHeight::Response::doToJson(rapidjson::Writer<epee::byte_str
void GetBlockHeaderByHeight::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, header, header);
}
@ -516,11 +395,6 @@ void GetBlockHeadersByHeight::Request::doToJson(rapidjson::Writer<epee::byte_str
void GetBlockHeadersByHeight::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, heights, heights);
}
@ -531,11 +405,6 @@ void GetBlockHeadersByHeight::Response::doToJson(rapidjson::Writer<epee::byte_st
void GetBlockHeadersByHeight::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, headers, headers);
}
@ -555,11 +424,6 @@ void GetPeerList::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void GetPeerList::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, white_list, white_list);
GET_FROM_JSON_OBJECT(val, gray_list, gray_list);
}
@ -572,11 +436,6 @@ void SetLogLevel::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void SetLogLevel::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, level, level);
}
@ -603,11 +462,6 @@ void GetTransactionPool::Response::doToJson(rapidjson::Writer<epee::byte_stream>
void GetTransactionPool::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, transactions, transactions);
GET_FROM_JSON_OBJECT(val, key_images, key_images);
}
@ -620,11 +474,6 @@ void HardForkInfo::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest)
void HardForkInfo::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, version, version);
}
@ -635,11 +484,6 @@ void HardForkInfo::Response::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void HardForkInfo::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, info, info);
}
@ -655,11 +499,6 @@ void GetOutputHistogram::Request::doToJson(rapidjson::Writer<epee::byte_stream>&
void GetOutputHistogram::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, amounts, amounts);
GET_FROM_JSON_OBJECT(val, min_count, min_count);
GET_FROM_JSON_OBJECT(val, max_count, max_count);
@ -674,11 +513,6 @@ void GetOutputHistogram::Response::doToJson(rapidjson::Writer<epee::byte_stream>
void GetOutputHistogram::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, histogram, histogram);
}
@ -690,11 +524,6 @@ void GetOutputKeys::Request::doToJson(rapidjson::Writer<epee::byte_stream>& dest
void GetOutputKeys::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, outputs, outputs);
}
@ -705,11 +534,6 @@ void GetOutputKeys::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
void GetOutputKeys::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, keys, keys);
}
@ -728,11 +552,6 @@ void GetRPCVersion::Response::doToJson(rapidjson::Writer<epee::byte_stream>& des
void GetRPCVersion::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, version, version);
}
@ -743,11 +562,6 @@ void GetFeeEstimate::Request::doToJson(rapidjson::Writer<epee::byte_stream>& des
void GetFeeEstimate::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
}
@ -761,11 +575,6 @@ void GetFeeEstimate::Response::doToJson(rapidjson::Writer<epee::byte_stream>& de
void GetFeeEstimate::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, estimated_base_fee, estimated_base_fee);
GET_FROM_JSON_OBJECT(val, fee_mask, fee_mask);
GET_FROM_JSON_OBJECT(val, size_scale, size_scale);
@ -782,11 +591,6 @@ void GetOutputDistribution::Request::doToJson(rapidjson::Writer<epee::byte_strea
void GetOutputDistribution::Request::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, amounts, amounts);
GET_FROM_JSON_OBJECT(val, from_height, from_height);
GET_FROM_JSON_OBJECT(val, to_height, to_height);
@ -801,11 +605,6 @@ void GetOutputDistribution::Response::doToJson(rapidjson::Writer<epee::byte_stre
void GetOutputDistribution::Response::fromJson(const rapidjson::Value& val)
{
if (!val.IsObject())
{
throw json::WRONG_TYPE("json object");
}
GET_FROM_JSON_OBJECT(val, status, status);
GET_FROM_JSON_OBJECT(val, distributions, distributions);
}

@ -158,22 +158,13 @@ void ZmqServer::serve()
if (!pub || sockets[2].revents)
{
expect<std::string> message = net::zmq::receive(rep.get(), read_flags);
if (!message)
{
// EAGAIN can occur when using `zmq_poll`, which doesn't inspect for message validity
if (message != net::zmq::make_error_code(EAGAIN))
MONERO_THROW(message.error(), "Read failure on ZMQ-RPC");
}
else // no errors
{
MDEBUG("Received RPC request: \"" << *message << "\"");
epee::byte_slice response = handler.handle(std::move(*message));
const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
MDEBUG("Sending RPC reply: \"" << response_view << "\"");
MONERO_UNWRAP(net::zmq::send(std::move(response), rep.get()));
}
std::string message = MONERO_UNWRAP(net::zmq::receive(rep.get(), read_flags));
MDEBUG("Received RPC request: \"" << message << "\"");
epee::byte_slice response = handler.handle(std::move(message));
const boost::string_ref response_view{reinterpret_cast<const char*>(response.data()), response.size()};
MDEBUG("Sending RPC reply: \"" << response_view << "\"");
MONERO_UNWRAP(net::zmq::send(std::move(response), rep.get()));
}
}
}

@ -42,7 +42,7 @@ namespace serialization
typename std::enable_if<!use_container_varint<T>(), bool>::type
serialize_container_element(Archive& ar, T& e)
{
return do_serialize(ar, e);
return ::do_serialize(ar, e);
}
template<typename Archive, typename T>
@ -52,7 +52,7 @@ namespace serialization
static constexpr const bool previously_varint = std::is_same<uint64_t, T>() || std::is_same<uint32_t, T>();
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
return do_serialize(ar, e);
return ::do_serialize(ar, e);
ar.serialize_varint(e);
return true;
}

@ -42,12 +42,14 @@ struct debug_archive : public json_archive<W> {
};
template <class T>
static inline bool do_serialize(debug_archive<true> &ar, T &v)
struct serializer<debug_archive<true>, T>
{
static void serialize(debug_archive<true> &ar, T &v)
{
ar.begin_object();
ar.tag(variant_serialization_traits<debug_archive<true>, T>::get_tag());
do_serialize(static_cast<json_archive<true>&>(ar), v);
serializer<json_archive<true>, T>::serialize(ar, v);
ar.end_object();
ar.stream() << std::endl;
return true;
}
}
};

@ -31,6 +31,8 @@
#include "cryptonote_basic/difficulty.h"
#include "serialization.h"
template<> struct is_basic_type<cryptonote::difficulty_type> { typedef boost::true_type type; };
template <template <bool> class Archive>
inline bool do_serialize(Archive<false>& ar, cryptonote::difficulty_type &diff)
{

@ -47,7 +47,7 @@ namespace serialization
typename std::enable_if<!use_pair_varint<T>(), bool>::type
serialize_pair_element(Archive& ar, T& e)
{
return do_serialize(ar, e);
return ::do_serialize(ar, e);
}
template<typename Archive, typename T>
@ -57,7 +57,7 @@ namespace serialization
static constexpr const bool previously_varint = std::is_same<uint64_t, T>();
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
return do_serialize(ar, e);
return ::do_serialize(ar, e);
ar.serialize_varint(e);
return true;
}

@ -57,30 +57,73 @@
template <class T>
struct is_blob_type { typedef boost::false_type type; };
/*! \fn do_serialize(Archive &ar, T &v)
/*! \struct has_free_serializer
*
* \brief a descriptor for dispatching serialize
*/
template <class T>
struct has_free_serializer { typedef boost::true_type type; };
/*! \struct is_basic_type
*
* \brief a descriptor for dispatching serialize
*/
template <class T>
struct is_basic_type { typedef boost::false_type type; };
template<typename F, typename S>
struct is_basic_type<std::pair<F,S>> { typedef boost::true_type type; };
template<>
struct is_basic_type<std::string> { typedef boost::true_type type; };
/*! \struct serializer
*
* \brief main function for dispatching serialization for a given pair of archive and value types
* \brief ... wouldn't a class be better?
*
* Types marked true with is_blob_type<T> will be serialized as a blob, integral types will be
* serialized as integers, and types who have a `member_do_serialize` method will be serialized
* using that method. Booleans are serialized like blobs.
* \detailed The logic behind serializing data. Places the archive
* data into the supplied parameter. This dispatches based on the
* supplied \a T template parameter's traits of is_blob_type or it is
* an integral (as defined by the is_integral trait). Depends on the
* \a Archive parameter to have overloaded the serialize_blob(T v,
* size_t size) and serialize_int(T v) base on which trait it
* applied. When the class has neither types, it falls to the
* overloaded method do_serialize(Archive ar) in T to do the work.
*/
template <class Archive, class T>
inline std::enable_if_t<is_blob_type<T>::type::value, bool> do_serialize(Archive &ar, T &v)
{
ar.serialize_blob(&v, sizeof(v));
return true;
}
template <class Archive, class T>
inline std::enable_if_t<boost::is_integral<T>::value, bool> do_serialize(Archive &ar, T &v)
{
ar.serialize_int(v);
return true;
}
struct serializer{
static bool serialize(Archive &ar, T &v) {
return serialize(ar, v, typename boost::is_integral<T>::type(), typename is_blob_type<T>::type(), typename is_basic_type<T>::type());
}
template<typename A>
static bool serialize(Archive &ar, T &v, boost::false_type, boost::true_type, A a) {
ar.serialize_blob(&v, sizeof(v));
return true;
}
template<typename A>
static bool serialize(Archive &ar, T &v, boost::true_type, boost::false_type, A a) {
ar.serialize_int(v);
return true;
}
static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type, boost::false_type) {
//serialize_custom(ar, v, typename has_free_serializer<T>::type());
return v.do_serialize(ar);
}
static bool serialize(Archive &ar, T &v, boost::false_type, boost::false_type, boost::true_type) {
//serialize_custom(ar, v, typename has_free_serializer<T>::type());
return do_serialize(ar, v);
}
static void serialize_custom(Archive &ar, T &v, boost::true_type) {
}
};
/*! \fn do_serialize(Archive &ar, T &v)
*
* \brief just calls the serialize function defined for ar and v...
*/
template <class Archive, class T>
inline auto do_serialize(Archive &ar, T &v) -> decltype(v.member_do_serialize(ar), true)
inline bool do_serialize(Archive &ar, T &v)
{
return v.member_do_serialize(ar);
return ::serializer<Archive, T>::serialize(ar, v);
}
template <class Archive>
inline bool do_serialize(Archive &ar, bool &v)
@ -101,6 +144,16 @@ inline bool do_serialize(Archive &ar, bool &v)
typedef boost::true_type type; \
}
/*! \macro FREE_SERIALIZER
*
* \brief adds the has_free_serializer to the type
*/
#define FREE_SERIALIZER(T) \
template<> \
struct has_free_serializer<T> { \
typedef boost::true_type type; \
}
/*! \macro VARIANT_TAG
*
* \brief Adds the tag \tag to the \a Archive of \a Type
@ -121,7 +174,7 @@ inline bool do_serialize(Archive &ar, bool &v)
*/
#define BEGIN_SERIALIZE() \
template <bool W, template <bool> class Archive> \
bool member_do_serialize(Archive<W> &ar) {
bool do_serialize(Archive<W> &ar) {
/*! \macro BEGIN_SERIALIZE_OBJECT
*
@ -130,7 +183,7 @@ inline bool do_serialize(Archive &ar, bool &v)
*/
#define BEGIN_SERIALIZE_OBJECT() \
template <bool W, template <bool> class Archive> \
bool member_do_serialize(Archive<W> &ar) { \
bool do_serialize(Archive<W> &ar) { \
ar.begin_object(); \
bool r = do_serialize_object(ar); \
ar.end_object(); \
@ -144,6 +197,11 @@ inline bool do_serialize(Archive &ar, bool &v)
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) \
::serialization::detail::prepare_custom_vector_serialization(size, vec, typename Archive<W>::is_saving())
/*! \macro PREPARE_CUSTOM_DEQUE_SERIALIZATION
*/
#define PREPARE_CUSTOM_DEQUE_SERIALIZATION(size, vec) \
::serialization::detail::prepare_custom_deque_serialization(size, vec, typename Archive<W>::is_saving())
/*! \macro END_SERIALIZE
* \brief self-explanatory
*/
@ -151,6 +209,16 @@ inline bool do_serialize(Archive &ar, bool &v)
return ar.good(); \
}
/*! \macro VALUE(f)
* \brief the same as FIELD(f)
*/
#define VALUE(f) \
do { \
ar.tag(#f); \
bool r = ::do_serialize(ar, f); \
if (!r || !ar.good()) return false; \
} while(0);
/*! \macro FIELD_N(t,f)
*
* \brief serializes a field \a f tagged \a t
@ -158,7 +226,7 @@ inline bool do_serialize(Archive &ar, bool &v)
#define FIELD_N(t, f) \
do { \
ar.tag(t); \
bool r = do_serialize(ar, f); \
bool r = ::do_serialize(ar, f); \
if (!r || !ar.good()) return false; \
} while(0);
@ -169,7 +237,7 @@ inline bool do_serialize(Archive &ar, bool &v)
#define FIELD(f) \
do { \
ar.tag(#f); \
bool r = do_serialize(ar, f); \
bool r = ::do_serialize(ar, f); \
if (!r || !ar.good()) return false; \
} while(0);
@ -179,7 +247,7 @@ inline bool do_serialize(Archive &ar, bool &v)
*/
#define FIELDS(f) \
do { \
bool r = do_serialize(ar, f); \
bool r = ::do_serialize(ar, f); \
if (!r || !ar.good()) return false; \
} while(0);
@ -249,6 +317,17 @@ namespace serialization {
vec.resize(size);
}
template <typename T>
void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<true>& /*is_saving*/)
{
}
template <typename T>
void prepare_custom_deque_serialization(size_t size, std::deque<T>& vec, const boost::mpl::bool_<false>& /*is_saving*/)
{
vec.resize(size);
}
/*! \fn do_check_stream_state
*
* \brief self explanatory

@ -39,7 +39,7 @@ namespace serialization
template <typename Archive, class T>
bool serialize_tuple_element(Archive& ar, T& e)
{
return do_serialize(ar, e);
return ::do_serialize(ar, e);
}
template <typename Archive>

@ -72,7 +72,7 @@ struct variant_reader
{
if(variant_serialization_traits<Archive, current_type>::get_tag() == t) {
current_type x;
if(!do_serialize(ar, x))
if(!::do_serialize(ar, x))
{
ar.set_fail();
return false;
@ -100,13 +100,19 @@ struct variant_reader<Archive, Variant, TBegin, TBegin>
}
};
template <template <bool> class Archive, typename... T>
static bool do_serialize(Archive<false> &ar, boost::variant<T...> &v) {
using types = typename boost::variant<T...>::types;
typename Archive<false>::variant_tag_type t;
template <template <bool> class Archive, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct serializer<Archive<false>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
{
typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type;
typedef typename Archive<false>::variant_tag_type variant_tag_type;
typedef typename variant_type::types types;
static bool serialize(Archive<false> &ar, variant_type &v) {
variant_tag_type t;
ar.begin_variant();
ar.read_variant_tag(t);
if(!variant_reader<Archive<false>, boost::variant<T...>,
if(!variant_reader<Archive<false>, variant_type,
typename boost::mpl::begin<types>::type,
typename boost::mpl::end<types>::type>::read(ar, v, t))
{
@ -115,21 +121,27 @@ static bool do_serialize(Archive<false> &ar, boost::variant<T...> &v) {
}
ar.end_variant();
return true;
}
}
};
template <template <bool> class Archive>
struct variant_write_visitor : public boost::static_visitor<bool>
template <template <bool> class Archive, BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct serializer<Archive<true>, boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>>
{
typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> variant_type;
//typedef typename Archive<true>::variant_tag_type variant_tag_type;
struct visitor : public boost::static_visitor<bool>
{
Archive<true> &ar;
variant_write_visitor(Archive<true> &a) : ar(a) { }
visitor(Archive<true> &a) : ar(a) { }
template <class T>
bool operator ()(T &rv) const
{
ar.begin_variant();
ar.write_variant_tag(variant_serialization_traits<Archive<true>, T>::get_tag());
if(!do_serialize(ar, rv))
if(!::do_serialize(ar, rv))
{
ar.set_fail();
return false;
@ -137,10 +149,9 @@ struct variant_write_visitor : public boost::static_visitor<bool>
ar.end_variant();
return true;
}
};
};
template <template <bool> class Archive, typename... T>
static bool do_serialize(Archive<true> &ar, boost::variant<T...> &v)
{
return boost::apply_visitor(variant_write_visitor<Archive>(ar), v);
}
static bool serialize(Archive<true> &ar, variant_type &v) {
return boost::apply_visitor(visitor(ar), v);
}
};

@ -196,7 +196,7 @@ namespace
const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=<N1>[,<N2>[,...]]]");
const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
const char* USAGE_PAYMENT_ID("payment_id");
const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [subtractfeefrom=<D0>[,<D1>,all,...]] [<payment_id>]");
const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]");
const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]");
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
@ -531,52 +531,7 @@ namespace
fail_msg_writer() << sw::tr("invalid format for subaddress lookahead; must be <major>:<minor>");
return r;
}
static constexpr const char* SFFD_ARG_NAME{"subtractfeefrom="};
bool parse_subtract_fee_from_outputs
(
const std::string& arg,
tools::wallet2::unique_index_container& subtract_fee_from_outputs,
bool& subtract_fee_from_all,
bool& matches
)
{
matches = false;
if (!boost::string_ref{arg}.starts_with(SFFD_ARG_NAME)) // if arg doesn't match
return true;
matches = true;
const char* arg_end = arg.c_str() + arg.size();
for (const char* p = arg.c_str() + strlen(SFFD_ARG_NAME); p < arg_end;)
{
const char* new_p = nullptr;
const unsigned long dest_index = strtoul(p, const_cast<char**>(&new_p), 10);
if (dest_index == 0 && new_p == p) // numerical conversion failed
{
if (0 != strncmp(p, "all", 3))
{
fail_msg_writer() << tr("Failed to parse subtractfeefrom list");
return false;
}
subtract_fee_from_all = true;
break;
}
else if (dest_index > std::numeric_limits<uint32_t>::max())
{
fail_msg_writer() << tr("Destination index is too large") << ": " << dest_index;
return false;
}
else
{
subtract_fee_from_outputs.insert(dest_index);
p = new_p + 1; // skip the comma
}
}
return true;
}
} // anonymous namespace
}
void simple_wallet::handle_transfer_exception(const std::exception_ptr &e, bool trusted_daemon)
{
@ -3351,7 +3306,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 <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)"));
m_cmd_binder.set_handler("locked_transfer",
boost::bind(&simple_wallet::on_command, this, &simple_wallet::locked_transfer,_1),
tr(USAGE_LOCKED_TRANSFER),
@ -6673,7 +6628,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
local_args.erase(local_args.begin());
}
uint32_t priority = m_wallet->get_default_priority();
uint32_t priority = 0;
if (local_args.size() > 0 && parse_priority(local_args[0], priority))
local_args.erase(local_args.begin());
@ -6754,27 +6709,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
local_args.pop_back();
}
// Parse subtractfeefrom destination list
tools::wallet2::unique_index_container subtract_fee_from_outputs;
bool subtract_fee_from_all = false;
for (auto it = local_args.begin(); it < local_args.end();)
{
bool matches = false;
if (!parse_subtract_fee_from_outputs(*it, subtract_fee_from_outputs, subtract_fee_from_all, matches))
{
return false;
}
else if (matches)
{
it = local_args.erase(it);
break;
}
else
{
++it;
}
}
vector<cryptonote::address_parse_info> dsts_info;
vector<cryptonote::tx_destination_entry> dsts;
for (size_t i = 0; i < local_args.size(); )
@ -6871,13 +6805,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
dsts.push_back(de);
}
if (subtract_fee_from_all)
{
subtract_fee_from_outputs.clear();
for (decltype(subtract_fee_from_outputs)::value_type i = 0; i < dsts.size(); ++i)
subtract_fee_from_outputs.insert(i);
}
SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return false;);
try
@ -6896,13 +6823,13 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
return false;
}
unlock_block = bc_height + locked_blocks;
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
break;
default:
LOG_ERROR("Unknown transfer method, using default");
/* FALLTHRU */
case Transfer:
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs);
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
break;
}

@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.11.2.0"
#define DEF_MONERO_VERSION "0.11.1.0"
#define DEF_MONERO_RELEASE_NAME "Kunty Karen"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@

@ -84,7 +84,6 @@ namespace Monero {
ci->m_unlocked = m_wallet->m_wallet->is_transfer_unlocked(td);
ci->m_pubKey = string_tools::pod_to_hex(td.get_public_key());
ci->m_coinbase = td.m_tx.vin.size() == 1 && td.m_tx.vin[0].type() == typeid(cryptonote::txin_gen);
ci->m_description = m_wallet->m_wallet->get_tx_note(td.m_txid);
m_rows.push_back(ci);
}

@ -113,10 +113,6 @@ namespace Monero {
bool CoinsInfoImpl::coinbase() const {
return m_coinbase;
}
string CoinsInfoImpl::description() const {
return m_description;
}
} // namespace
namespace Bitmonero = Monero;

@ -35,7 +35,6 @@ namespace Monero {
virtual bool unlocked() const override;
virtual std::string pubKey() const override;
virtual bool coinbase() const override;
virtual std::string description() const override;
private:
uint64_t m_blockHeight;
@ -58,7 +57,6 @@ namespace Monero {
bool m_unlocked;
std::string m_pubKey;
bool m_coinbase;
std::string m_description;
friend class CoinsImpl;

@ -79,22 +79,6 @@ std::vector<std::string> PendingTransactionImpl::txid() const
return txid;
}
std::vector<std::string> PendingTransactionImpl::hex() const
{
std::vector<std::string> hexs;
for (const auto &pt: m_pending_tx)
hexs.push_back(epee::string_tools::buff_to_hex_nodelimer(cryptonote::tx_to_blob(pt.tx)));
return hexs;
}
std::vector<std::string> PendingTransactionImpl::txKey() const
{
std::vector<std::string> keys;
for (const auto& pt: m_pending_tx)
keys.push_back(epee::string_tools::pod_to_hex(pt.tx_key));
return keys;
}
bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite)
{

@ -66,8 +66,6 @@ public:
std::string multisigSignData() override;
void signMultisigTx() override;
std::vector<std::string> signersKeys() const override;
std::vector<std::string> hex() const override;
std::vector<std::string> txKey() const override;
private:
friend class WalletImpl;

@ -434,9 +434,6 @@ WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds)
m_refreshIntervalMillis = DEFAULT_REFRESH_INTERVAL_MILLIS;
m_refreshThread = boost::thread([this] () {
this->refreshThreadFunc();
});
}
WalletImpl::~WalletImpl()
@ -1211,8 +1208,8 @@ UnsignedTransaction *WalletImpl::loadUnsignedTxFromStr(const std::string &unsign
// Check tx data and construct confirmation message
std::string extra_message;
if (!std::get<2>(transaction->m_unsigned_tx_set.transfers).empty())
extra_message = (boost::format("%u outputs to import. ") % (unsigned)std::get<2>(transaction->m_unsigned_tx_set.transfers).size()).str();
if (!transaction->m_unsigned_tx_set.transfers.second.empty())
extra_message = (boost::format("%u outputs to import. ") % (unsigned)transaction->m_unsigned_tx_set.transfers.second.size()).str();
transaction->checkLoadedTx([&transaction](){return transaction->m_unsigned_tx_set.txes.size();}, [&transaction](size_t n)->const tools::wallet2::tx_construction_data&{return transaction->m_unsigned_tx_set.txes[n];}, extra_message);
setStatus(transaction->status(), transaction->errorString());
@ -1680,13 +1677,13 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat
// - unconfirmed_transfer_details;
// - confirmed_transfer_details)
PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<string> &dst_addr, const string &payment_id, optional<std::vector<uint64_t>> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::set<std::string> &preferred_inputs)
PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<string> &dst_addr, const string &payment_id, optional<std::vector<uint64_t>> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
clearStatus();
// Pause refresh thread while creating transaction
pauseRefresh();
cryptonote::address_parse_info info;
uint32_t adjusted_priority = m_wallet->adjust_priority(static_cast<uint32_t>(priority));
@ -1746,19 +1743,6 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
}
}
}
std::vector<crypto::key_image> preferred_input_list;
if (!preferred_inputs.empty()) {
for (const auto &public_key : preferred_inputs) {
crypto::key_image keyImage;
bool r = epee::string_tools::hex_to_pod(public_key, keyImage);
if (!r) {
error = true;
setStatusError(tr("failed to parse key image"));
break;
}
preferred_input_list.push_back(keyImage);
}
}
if (error) {
break;
}
@ -1773,11 +1757,11 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
if (amount) {
transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
adjusted_priority,
extra, subaddr_account, subaddr_indices, preferred_input_list);
extra, subaddr_account, subaddr_indices);
} else {
transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */,
adjusted_priority,
extra, subaddr_account, subaddr_indices, preferred_input_list);
extra, subaddr_account, subaddr_indices);
}
pendingTxPostProcess(transaction);
@ -1858,10 +1842,10 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
}
PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::set<std::string> &preferred_inputs)
PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
{
return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices, preferred_inputs);
return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices);
}
PendingTransaction *WalletImpl::createTransactionSingle(const string &key_image, const string &dst_addr,
@ -2601,7 +2585,7 @@ void WalletImpl::doRefresh()
LOG_PRINT_L3(__FUNCTION__ << ": doRefresh, rescan = "<<rescan);
if(rescan)
m_wallet->rescan_blockchain(false);
m_wallet->refresh(true);
m_wallet->refresh(trustedDaemon());
if (!m_synchronized) {
m_synchronized = true;
}

@ -164,14 +164,13 @@ public:
optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {},
const std::set<std::string> &preferred_inputs = {}) override;
std::set<uint32_t> subaddr_indices = {}) override;
PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {},
const std::set<std::string> &preferred_inputs = {}) override;
std::set<uint32_t> subaddr_indices = {}) override;
PendingTransaction * createTransactionSingle(const std::string &key_image, const std::string &dst_addr,
size_t outputs = 1, PendingTransaction::Priority priority = PendingTransaction::Priority_Low) override;

@ -174,8 +174,6 @@ struct PendingTransaction
* @return vector of base58-encoded signers' public keys
*/
virtual std::vector<std::string> signersKeys() const = 0;
virtual std::vector<std::string> hex() const = 0;
virtual std::vector<std::string> txKey() const = 0;
};
/**
@ -342,7 +340,6 @@ struct CoinsInfo
virtual bool unlocked() const = 0;
virtual std::string pubKey() const = 0;
virtual bool coinbase() const = 0;
virtual std::string description() const = 0;
};
struct Coins
@ -935,7 +932,6 @@ struct Wallet
* \param subaddr_account subaddress account from which the input funds are taken
* \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices
* \param priority
* \param preferred_inputs optional set of key_image strings from preferred inputs
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
* after object returned
*/
@ -944,7 +940,7 @@ struct Wallet
optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
PendingTransaction::Priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {}, const std::set<std::string> &preferred_inputs = {}) = 0;
std::set<uint32_t> subaddr_indices = {}) = 0;
/*!
* \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
@ -955,7 +951,6 @@ struct Wallet
* \param subaddr_account subaddress account from which the input funds are taken
* \param subaddr_indices set of subaddress indices to use for transfer or sweeping. if set empty, all are chosen when sweeping, and one or more are automatically chosen when transferring. after execution, returns the set of actually used indices
* \param priority
* \param preferred_inputs optional set of key_image strings from preferred inputs
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
* after object returned
*/
@ -964,8 +959,7 @@ struct Wallet
optional<uint64_t> amount, uint32_t mixin_count,
PendingTransaction::Priority = PendingTransaction::Priority_Low,
uint32_t subaddr_account = 0,
std::set<uint32_t> subaddr_indices = {},
const std::set<std::string> &preferred_inputs = {}) = 0;
std::set<uint32_t> subaddr_indices = {}) = 0;
/*!
* \brief createTransactionSingle creates transaction with single input

@ -218,17 +218,6 @@ namespace
return reason;
}
bool is_preferred_input(const std::vector<crypto::key_image>& preferred_input_list, const crypto::key_image& input) {
bool res = true;
if (preferred_input_list.size() > 0) {
auto it = std::find(preferred_input_list.begin(), preferred_input_list.end(), input);
if (it == preferred_input_list.end()) {
res = false;
}
}
return res;
}
size_t get_num_outputs(const std::vector<cryptonote::tx_destination_entry> &dsts, const std::vector<tools::wallet2::transfer_details> &transfers, const std::vector<size_t> &selected_transfers)
{
size_t outputs = dsts.size();
@ -4404,10 +4393,7 @@ void wallet2::handle_reorg(uint64_t height, std::map<std::pair<uint64_t, uint64_
// C
THROW_WALLET_EXCEPTION_IF(height < m_blockchain.offset() && m_blockchain.size() > m_blockchain.offset(),
error::wallet_internal_error, "Daemon claims reorg below last checkpoint");
detached_blockchain_data dbd = detach_blockchain(height, output_tracker_cache);
if (m_callback)
m_callback->on_reorg(height, dbd.detached_blockchain.size(), dbd.detached_tx_hashes.size());
detach_blockchain(height, output_tracker_cache);
}
//----------------------------------------------------------------------------------------------------
bool wallet2::deinit()
@ -6642,20 +6628,6 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
if (!m_persistent_rpc_client_id)
set_rpc_client_secret_key(rct::rct2sk(rct::skGen()));
// Wallets used to wipe, but not erase, old unused multisig key info, which lead to huge memory leaks.
// Here we erase these multisig keys if they're zero'd out to free up space.
for (auto &td : m_transfers)
{
auto mk_it = td.m_multisig_k.begin();
while (mk_it != td.m_multisig_k.end())
{
if (*mk_it == rct::zero())
mk_it = td.m_multisig_k.erase(mk_it);
else
++mk_it;
}
}
cryptonote::block genesis;
generate_genesis(genesis);
crypto::hash genesis_hash = get_block_hash(genesis);
@ -7535,10 +7507,7 @@ void wallet2::commit_tx(pending_tx& ptx)
// tx generated, get rid of used k values
for (size_t idx: ptx.selected_transfers)
{
memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
m_transfers[idx].m_multisig_k.clear();
}
//fee includes dust if dust policy specified it.
LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
@ -8042,10 +8011,7 @@ std::string wallet2::save_multisig_tx(multisig_tx_set txs)
// txes generated, get rid of used k values
for (size_t n = 0; n < txs.m_ptx.size(); ++n)
for (size_t idx: txs.m_ptx[n].construction_data.selected_transfers)
{
memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
m_transfers[idx].m_multisig_k.clear();
}
// zero out some data we don't want to share
for (auto &ptx: txs.m_ptx)
@ -8369,10 +8335,7 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto
// inputs in the transactions worked on here)
for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n)
for (size_t idx: exported_txs.m_ptx[n].construction_data.selected_transfers)
{
memwipe(m_transfers[idx].m_multisig_k.data(), m_transfers[idx].m_multisig_k.size() * sizeof(m_transfers[idx].m_multisig_k[0]));
m_transfers[idx].m_multisig_k.clear();
}
exported_txs.m_signers.insert(get_multisig_signer_public_key());
@ -8601,7 +8564,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
else if (blocks[0].first > 0)
{
MINFO("We don't use the low priority because there's a backlog in the tx pool.");
return 2;
return priority;
}
// get the current full reward zone
@ -8649,7 +8612,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority)
if (P > 80)
{
MINFO("We don't use the low priority because recent blocks are quite full.");
return 2;
return priority;
}
MINFO("We'll use the low priority because probably it's safe to do so.");
return 1;
@ -9301,26 +9264,6 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
COMMAND_RPC_GET_OUTPUTS_BIN::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_GET_OUTPUTS_BIN::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
// The secret picking order contains outputs in the order that we selected them.
//
// We will later sort the output request entries in a pre-determined order so that the daemon
// that we're requesting information from doesn't learn any information about the true spend
// for each ring. However, internally, we want to prefer to construct our rings using the
// outputs that we picked first versus outputs picked later.
//
// The reason why is because each consecutive output pick within a ring becomes increasing less
// statistically independent from other picks, since we pick outputs from a finite set
// *without replacement*, due to the protocol not allowing duplicate ring members. This effect
// is exacerbated by the fact that we pick 1.5x + 75 as many outputs as we need per RPC
// request to account for unusable outputs. This effect is small, but non-neglibile and gets
// worse with larger ring sizes.
std::vector<get_outputs_out> secret_picking_order;
// Convenience/safety lambda to make sure that both output lists req.outputs and secret_picking_order are updated together
// Each ring section of req.outputs gets sorted later after selecting all outputs for that ring
const auto add_output_to_lists = [&req, &secret_picking_order](const get_outputs_out &goo)
{ req.outputs.push_back(goo); secret_picking_order.push_back(goo); };
std::unique_ptr<gamma_picker> gamma;
if (has_rct)
gamma.reset(new gamma_picker(rct_offsets));
@ -9455,7 +9398,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (out < num_outs)
{
MINFO("Using it");
add_output_to_lists({amount, out});
req.outputs.push_back({amount, out});
++num_found;
seen_indices.emplace(out);
if (out == td.m_global_output_index)
@ -9477,12 +9420,12 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
if (num_outs <= requested_outputs_count)
{
for (uint64_t i = 0; i < num_outs; i++)
add_output_to_lists({amount, i});
req.outputs.push_back({amount, i});
// duplicate to make up shortfall: this will be caught after the RPC call,
// so we can also output the amounts for which we can't reach the required
// mixin after checking the actual unlockedness
for (uint64_t i = num_outs; i < requested_outputs_count; ++i)
add_output_to_lists({amount, num_outs - 1});
req.outputs.push_back({amount, num_outs - 1});
}
else
{
@ -9491,7 +9434,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
{
num_found = 1;
seen_indices.emplace(td.m_global_output_index);
add_output_to_lists({amount, td.m_global_output_index});
req.outputs.push_back({amount, td.m_global_output_index});
LOG_PRINT_L1("Selecting real output: " << td.m_global_output_index << " for " << print_money(amount));
}
@ -9599,7 +9542,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
seen_indices.emplace(i);
picks[type].insert(i);
add_output_to_lists({amount, i});
req.outputs.push_back({amount, i});
++num_found;
MDEBUG("picked " << i << ", " << num_found << " now picked");
}
@ -9613,7 +9556,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
// we'll error out later
while (num_found < requested_outputs_count)
{
add_output_to_lists({amount, 0});
req.outputs.push_back({amount, 0});
++num_found;
}
}
@ -9623,10 +9566,6 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
[](const get_outputs_out &a, const get_outputs_out &b) { return a.index < b.index; });
}
THROW_WALLET_EXCEPTION_IF(req.outputs.size() != secret_picking_order.size(), error::wallet_internal_error,
"bug: we did not update req.outputs/secret_picking_order in tandem");
// List all requested outputs to debug log
if (ELPP->vRegistry()->allowed(el::Level::Debug, MONERO_DEFAULT_LOG_CATEGORY))
{
std::map<uint64_t, std::set<uint64_t>> outs;
@ -9747,21 +9686,18 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
}
}
// While we are still lacking outputs in this result ring, in our secret pick order...
// then pick others in random order till we reach the required number
// since we use an equiprobable pick here, we don't upset the triangular distribution
std::vector<size_t> order;
order.resize(requested_outputs_count);
for (size_t n = 0; n < order.size(); ++n)
order[n] = n;
std::shuffle(order.begin(), order.end(), crypto::random_device{});
LOG_PRINT_L2("Looking for " << (fake_outputs_count+1) << " outputs of size " << print_money(td.is_rct() ? 0 : td.amount()));
for (size_t ring_pick_idx = base; ring_pick_idx < base + requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++ring_pick_idx)
for (size_t o = 0; o < requested_outputs_count && outs.back().size() < fake_outputs_count + 1; ++o)
{
const get_outputs_out attempted_output = secret_picking_order[ring_pick_idx];
// Find the index i of our pick in the request/response arrays
size_t i;
for (i = base; i < base + requested_outputs_count; ++i)
if (req.outputs[i].index == attempted_output.index)
break;
THROW_WALLET_EXCEPTION_IF(i == base + requested_outputs_count, error::wallet_internal_error,
"Could not find index of picked output in requested outputs");
// Try adding this output's information to result ring if output isn't invalid
size_t i = base + order[o];
LOG_PRINT_L2("Index " << i << "/" << requested_outputs_count << ": idx " << req.outputs[i].index << " (real " << td.m_global_output_index << "), unlocked " << daemon_resp.outs[i].unlocked << ", key " << daemon_resp.outs[i].key);
tx_add_fake_output(outs, req.outputs[i].index, daemon_resp.outs[i].key, daemon_resp.outs[i].mask, td.m_global_output_index, daemon_resp.outs[i].unlocked, valid_public_keys_cache);
}
@ -10328,7 +10264,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
LOG_PRINT_L2("transfer_selected_rct done");
}
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list)
std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices)
{
std::vector<size_t> picks;
float current_output_relatdness = 1.0f;
@ -10339,10 +10275,6 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (!is_spent(td, false) && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below)
@ -10363,10 +10295,6 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below)
@ -10378,10 +10306,6 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t j = i + 1; j < m_transfers.size(); ++j)
{
const transfer_details& td2 = m_transfers[j];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (td2.amount() > m_ignore_outputs_above || td2.amount() < m_ignore_outputs_below)
{
MDEBUG("Ignoring output " << j << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
@ -10954,7 +10878,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, const unique_index_container& subtract_fee_from_outputs, const std::vector<crypto::key_image>& preferred_input_list)
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();
@ -10969,12 +10893,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
std::vector<std::pair<uint32_t, std::vector<size_t>>> unused_transfers_indices_per_subaddr;
std::vector<std::pair<uint32_t, std::vector<size_t>>> unused_dust_indices_per_subaddr;
uint64_t needed_money, total_needed_money; // 'needed_money' is the sum of the destination amounts, while 'total_needed_money' includes 'needed_money' plus the fee if not 'subtract_fee_from_outputs'
uint64_t needed_money;
uint64_t accumulated_fee, accumulated_change;
struct TX {
std::vector<size_t> selected_transfers;
std::vector<cryptonote::tx_destination_entry> dsts;
std::vector<bool> dsts_are_fee_subtractable;
cryptonote::transaction tx;
pending_tx ptx;
size_t weight;
@ -10984,11 +10907,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
TX() : weight(0), needed_fee(0) {}
/* Add an output to the transaction.
* If merge_destinations is true, when adding a destination with an existing address, to increment the amount of the existing tx output instead of creating a new one
* If subtracting_fee is true, when we generate a final list of destinations for transfer_selected[_rct], this destination will be used to fund the tx fee
* Returns True if the output was added, False if there are no more available output slots.
*/
bool add(const cryptonote::tx_destination_entry &de, uint64_t amount, unsigned int original_output_index, bool merge_destinations, size_t max_dsts, bool subtracting_fee) {
bool add(const cryptonote::tx_destination_entry &de, uint64_t amount, unsigned int original_output_index, bool merge_destinations, size_t max_dsts) {
if (merge_destinations)
{
std::vector<cryptonote::tx_destination_entry>::iterator i;
@ -10998,7 +10919,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
if (dsts.size() >= max_dsts)
return false;
dsts.push_back(de);
dsts_are_fee_subtractable.push_back(subtracting_fee);
i = dsts.end() - 1;
i->amount = 0;
}
@ -11014,67 +10934,13 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
return false;
dsts.push_back(de);
dsts.back().amount = 0;
dsts_are_fee_subtractable.push_back(subtracting_fee);
}
THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &de.addr, sizeof(de.addr)), error::wallet_internal_error, "Mismatched destination address");
dsts[original_output_index].amount += amount;
}
return true;
}
// Returns destinations adjusted for given fee if subtract_fee_from_outputs is enabled
std::vector<cryptonote::tx_destination_entry> get_adjusted_dsts(uint64_t needed_fee) const
{
uint64_t dest_total = 0;
uint64_t subtractable_dest_total = 0;
std::vector<size_t> subtractable_indices;
subtractable_indices.reserve(dsts.size());
for (size_t i = 0; i < dsts.size(); ++i)
{
dest_total += dsts[i].amount;
if (dsts_are_fee_subtractable[i])
{
subtractable_dest_total += dsts[i].amount;
subtractable_indices.push_back(i);
}
}
if (subtractable_indices.empty()) // if subtract_fee_from_outputs is not enabled for this tx
return dsts;
THROW_WALLET_EXCEPTION_IF(subtractable_dest_total < needed_fee, error::tx_not_possible,
subtractable_dest_total, dest_total, needed_fee);
std::vector<cryptonote::tx_destination_entry> res = dsts;
// subtract fees from destinations equally, rounded down, until dust is left where we subtract 1
uint64_t subtractable_remaining = needed_fee;
auto si_it = subtractable_indices.cbegin();
uint64_t amount_to_subtract = 0;
while (subtractable_remaining)
{
// Set the amount to subtract iterating at the beginning of the list so equal amounts are
// subtracted throughout the list of destinations. We use max(x, 1) so that we we still step
// forwards even when the amount remaining is less than the number of subtractable indices
if (si_it == subtractable_indices.cbegin())
amount_to_subtract = std::max<uint64_t>(subtractable_remaining / subtractable_indices.size(), 1);
cryptonote::tx_destination_entry& d = res[*si_it];
THROW_WALLET_EXCEPTION_IF(d.amount <= amount_to_subtract, error::zero_amount);
subtractable_remaining -= amount_to_subtract;
d.amount -= amount_to_subtract;
++si_it;
// Wrap around to first subtractable index once we hit the end of the list
if (si_it == subtractable_indices.cend())
si_it = subtractable_indices.cbegin();
}
return res;
}
};
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;
@ -11097,14 +10963,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// throw if attempting a transaction with no destinations
THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination);
// throw if subtract_fee_from_outputs has a bad index
THROW_WALLET_EXCEPTION_IF(subtract_fee_from_outputs.size() && *subtract_fee_from_outputs.crbegin() >= dsts.size(),
error::subtract_fee_from_bad_index, *subtract_fee_from_outputs.crbegin());
// throw if subtract_fee_from_outputs is enabled and we have too many outputs to fit into one tx
THROW_WALLET_EXCEPTION_IF(subtract_fee_from_outputs.size() && dsts.size() > BULLETPROOF_MAX_OUTPUTS - 1,
error::wallet_internal_error, "subtractfeefrom transfers cannot be split over multiple transactions yet");
// calculate total amount being sent to all destinations
// throw if total amount overflows uint64_t
needed_money = 0;
@ -11132,7 +10990,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// 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 = (base_fee * estimate_tx_size(use_rct, 1, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags));
total_needed_money = needed_money + (subtract_fee_from_outputs.size() ? 0 : min_fee);
uint64_t balance_subtotal = 0;
uint64_t unlocked_balance_subtotal = 0;
for (uint32_t index_minor : subaddr_indices)
@ -11140,10 +10997,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
balance_subtotal += balance_per_subaddr[index_minor];
unlocked_balance_subtotal += unlocked_balance_per_subaddr[index_minor].first;
}
THROW_WALLET_EXCEPTION_IF(total_needed_money > balance_subtotal || min_fee > balance_subtotal, error::not_enough_money,
THROW_WALLET_EXCEPTION_IF(needed_money + min_fee > balance_subtotal, error::not_enough_money,
balance_subtotal, needed_money, 0);
// first check overall balance is enough, then unlocked one, so we throw distinct exceptions
THROW_WALLET_EXCEPTION_IF(total_needed_money > unlocked_balance_subtotal || min_fee > unlocked_balance_subtotal, error::not_enough_unlocked_money,
THROW_WALLET_EXCEPTION_IF(needed_money + min_fee > unlocked_balance_subtotal, error::not_enough_unlocked_money,
unlocked_balance_subtotal, needed_money, 0);
for (uint32_t i : subaddr_indices)
@ -11162,10 +11019,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
{
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below fractional threshold " << print_money(fractional_threshold));
@ -11250,8 +11103,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 = estimate_fee(use_per_byte_fee, use_rct, 2, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags, base_fee, fee_quantization_mask);
total_needed_money = needed_money + (subtract_fee_from_outputs.size() ? 0 : estimated_fee);
preferred_inputs = pick_preferred_rct_inputs(total_needed_money, subaddr_account, subaddr_indices, preferred_input_list);
preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices);
if (!preferred_inputs.empty())
{
string s;
@ -11284,10 +11136,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// - we have something to send
// - or we need to gather more fee
// - or we have just one input in that tx, which is rct (to try and make all/most rct txes 2/2)
unsigned int original_output_index = 0, destination_index = 0;
unsigned int original_output_index = 0;
std::vector<size_t>* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second;
std::vector<size_t>* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second;
hwdev.set_mode(hw::device::TRANSACTION_CREATE_FAKE);
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();
@ -11367,8 +11219,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// 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) <<
" for " << print_money(dsts[0].amount));
const bool subtract_fee_from_this_dest = subtract_fee_from_outputs.count(destination_index);
if (!tx.add(dsts[0], dsts[0].amount, original_output_index, m_merge_destinations, BULLETPROOF_MAX_OUTPUTS-1, subtract_fee_from_this_dest))
if (!tx.add(dsts[0], dsts[0].amount, original_output_index, m_merge_destinations, BULLETPROOF_MAX_OUTPUTS-1))
{
LOG_PRINT_L2("Didn't pay: ran out of output slots");
out_slots_exhausted = true;
@ -11378,7 +11229,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
dsts[0].amount = 0;
pop_index(dsts, 0);
++original_output_index;
++destination_index;
}
if (!out_slots_exhausted && available_amount > 0 && !dsts.empty() &&
@ -11386,8 +11236,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// 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));
const bool subtract_fee_from_this_dest = subtract_fee_from_outputs.count(destination_index);
if (tx.add(dsts[0], available_amount, original_output_index, m_merge_destinations, BULLETPROOF_MAX_OUTPUTS-1, subtract_fee_from_this_dest))
if (tx.add(dsts[0], available_amount, original_output_index, m_merge_destinations, BULLETPROOF_MAX_OUTPUTS-1))
{
dsts[0].amount -= available_amount;
available_amount = 0;
@ -11466,13 +11315,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// Try to carve the estimated fee from the partial payment (if there is one)
available_for_fee = try_carving_from_partial_payment(needed_fee, available_for_fee);
uint64_t inputs = 0, outputs = 0;
uint64_t inputs = 0, outputs = needed_fee;
for (size_t idx: tx.selected_transfers) inputs += m_transfers[idx].amount();
for (const auto &o: tx.dsts) outputs += o.amount;
if (subtract_fee_from_outputs.empty()) // if normal tx that doesn't subtract fees
{
outputs += needed_fee;
}
if (inputs < outputs)
{
@ -11483,32 +11328,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
tx.selected_transfers.size() << " inputs");
auto tx_dsts = tx.get_adjusted_dsts(needed_fee);
if (use_rct)
transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags);
else
transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
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_quantization_mask);
// Depending on the mode, we take extra fees from either our change output or the destination outputs for which subtract_fee_from_outputs is true
uint64_t output_available_for_fee = 0;
bool tx_has_subtractable_output = false;
for (size_t di = 0; di < tx.dsts.size(); ++di)
{
if (tx.dsts_are_fee_subtractable[di])
{
output_available_for_fee += tx.dsts[di].amount;
tx_has_subtractable_output = true;
}
}
if (!tx_has_subtractable_output)
{
output_available_for_fee = test_ptx.change_dts.amount;
}
available_for_fee = test_ptx.fee + output_available_for_fee + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0);
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_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(available_for_fee) << " available for fee (" <<
print_money(needed_fee) << " needed)");
@ -11524,24 +11352,18 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
else
{
LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee));
size_t fee_tries;
for (fee_tries = 0; fee_tries < 10 && needed_fee > test_ptx.fee; ++fee_tries) {
tx_dsts = tx.get_adjusted_dsts(needed_fee);
do {
if (use_rct)
transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
test_tx, test_ptx, rct_config, use_view_tags);
else
transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra,
detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags);
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_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");
};
THROW_WALLET_EXCEPTION_IF(fee_tries == 10, error::wallet_internal_error,
"Too many attempts to raise pending tx fee to level of needed fee");
} while (needed_fee > 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");
@ -11594,13 +11416,10 @@ skip_tx:
for (std::vector<TX>::iterator i = txes.begin(); i != txes.end(); ++i)
{
TX &tx = *i;
const auto tx_dsts = tx.get_adjusted_dsts(tx.needed_fee);
cryptonote::transaction test_tx;
pending_tx test_ptx;
if (use_rct) {
transfer_selected_rct(tx_dsts, /* NOMOD std::vector<cryptonote::tx_destination_entry> dsts,*/
transfer_selected_rct(tx.dsts, /* NOMOD std::vector<cryptonote::tx_destination_entry> dsts,*/
tx.selected_transfers, /* const std::list<size_t> selected_transfers */
fake_outs_count, /* CONST size_t fake_outputs_count, */
tx.outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */
@ -11613,7 +11432,7 @@ skip_tx:
rct_config,
use_view_tags); /* const bool use_view_tags */
} else {
transfer_selected(tx_dsts,
transfer_selected(tx.dsts,
tx.selected_transfers,
fake_outs_count,
tx.outs,
@ -11647,38 +11466,23 @@ skip_tx:
ptx_vector.push_back(tx.ptx);
}
THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, original_dsts, subtract_fee_from_outputs), error::wallet_internal_error, "Created transaction(s) failed sanity check");
THROW_WALLET_EXCEPTION_IF(!sanity_check(ptx_vector, original_dsts), error::wallet_internal_error, "Created transaction(s) failed sanity check");
// if we made it this far, we're OK to actually send the transactions
return ptx_vector;
}
bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, const std::vector<cryptonote::tx_destination_entry>& dsts, const unique_index_container& subtract_fee_from_outputs) const
bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, std::vector<cryptonote::tx_destination_entry> dsts) const
{
MDEBUG("sanity_check: " << ptx_vector.size() << " txes, " << dsts.size() << " destinations, subtract_fee_from_outputs " <<
(subtract_fee_from_outputs.size() ? "enabled" : "disabled"));
MDEBUG("sanity_check: " << ptx_vector.size() << " txes, " << dsts.size() << " destinations");
THROW_WALLET_EXCEPTION_IF(ptx_vector.empty(), error::wallet_internal_error, "No transactions");
THROW_WALLET_EXCEPTION_IF(!subtract_fee_from_outputs.empty() && ptx_vector.size() != 1,
error::wallet_internal_error, "feature subtractfeefrom not supported for split transactions");
// For destinations from where the fee is subtracted, the required amount has to be at least
// target amount - (tx fee / num_subtractable + 1). +1 since fee might not be evenly divisble by
// the number of subtractble destinations. For non-subtractable destinations, we need at least
// the target amount.
const size_t num_subtractable_dests = subtract_fee_from_outputs.size();
const uint64_t fee0 = ptx_vector[0].fee;
const uint64_t subtractable_fee_deduction = fee0 / std::max<size_t>(num_subtractable_dests, 1) + 1;
// check every party in there does receive at least the required amount
std::unordered_map<account_public_address, std::pair<uint64_t, bool>> required;
for (size_t i = 0; i < dsts.size(); ++i)
for (const auto &d: dsts)
{
const cryptonote::tx_destination_entry& d = dsts[i];
const bool dest_is_subtractable = subtract_fee_from_outputs.count(i);
const uint64_t fee_deduction = dest_is_subtractable ? subtractable_fee_deduction : 0;
const uint64_t required_amount = d.amount - std::min(fee_deduction, d.amount);
required[d.addr].first += required_amount;
required[d.addr].first += d.amount;
required[d.addr].second = d.is_subaddress;
}
@ -11732,7 +11536,7 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, c
return true;
}
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, const std::vector<crypto::key_image>& preferred_input_list)
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_dust_indices;
@ -11761,10 +11565,6 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
continue;
}
if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
{
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
@ -14835,10 +14635,7 @@ cryptonote::blobdata wallet2::export_multisig()
transfer_details &td = m_transfers[n];
crypto::key_image ki;
if (td.m_multisig_k.size())
{
memwipe(td.m_multisig_k.data(), td.m_multisig_k.size() * sizeof(td.m_multisig_k[0]));
td.m_multisig_k.clear();
}
info[n].m_LR.clear();
info[n].m_partial_key_images.clear();

@ -139,7 +139,6 @@ private:
public:
// Full wallet callbacks
virtual void on_new_block(uint64_t height, const cryptonote::block& block) {}
virtual void on_reorg(uint64_t height, uint64_t blocks_detached, size_t transfers_detached) {}
virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) {}
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {}
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index) {}
@ -599,7 +598,6 @@ private:
typedef std::vector<transfer_details> transfer_container;
typedef serializable_unordered_multimap<crypto::hash, payment_details> payment_container;
typedef std::set<uint32_t> unique_index_container;
struct multisig_sig
{
@ -1114,11 +1112,11 @@ private:
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<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, const unique_index_container& subtract_fee_from_outputs = {}, const std::vector<crypto::key_image>& preferred_input_list = {}); // 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 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, const std::vector<crypto::key_image>& preferred_input_list = {});
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 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 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, 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 sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, const std::vector<cryptonote::tx_destination_entry>& dsts, const unique_index_container& subtract_fee_from_outputs = {}) const;
bool sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, std::vector<cryptonote::tx_destination_entry> dsts) const;
void cold_tx_aux_import(const std::vector<pending_tx>& ptx, const std::vector<std::string>& tx_device_aux);
void cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux);
uint64_t cold_key_image_sync(uint64_t &spent, uint64_t &unspent);
@ -1799,7 +1797,7 @@ private:
std::vector<uint64_t> get_unspent_amounts_vector(bool strict);
uint64_t get_dynamic_base_fee_estimate();
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 std::vector<crypto::key_image>& preferred_input_list);
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices);
void set_spent(size_t idx, uint64_t height);
void set_unspent(size_t idx);
bool is_spent(const transfer_details &td, bool strict = true) const;

@ -85,7 +85,6 @@ namespace tools
// tx_too_big
// zero_amount
// zero_destination
// subtract_fee_from_bad_index
// wallet_rpc_error *
// daemon_busy
// no_connection_to_daemon
@ -780,15 +779,6 @@ namespace tools
}
};
//----------------------------------------------------------------------------------------------------
struct subtract_fee_from_bad_index : public transfer_error
{
explicit subtract_fee_from_bad_index(std::string&& loc, long bad_index)
: transfer_error(std::move(loc),
"subtractfeefrom: bad index: " + std::to_string(bad_index) + " (indexes are 0-based)")
{
}
};
//----------------------------------------------------------------------------------------------------
struct wallet_rpc_error : public wallet_logic_error
{
const std::string& request() const { return m_request; }

@ -987,9 +987,9 @@ namespace tools
return amount;
}
//------------------------------------------------------------------------------------------------------------------------------
template<typename Ts, typename Tu, typename Tk, typename Ta>
template<typename Ts, typename Tu, typename Tk>
bool wallet_rpc_server::fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector,
bool get_tx_key, Ts& tx_key, Tu &amount, Ta &amounts_by_dest, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay,
bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay,
Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, Tk &spent_key_images, epee::json_rpc::error &er)
{
for (const auto & ptx : ptx_vector)
@ -1006,12 +1006,6 @@ namespace tools
fill(fee, ptx.fee);
fill(weight, cryptonote::get_transaction_weight(ptx.tx));
// add amounts by destination
tools::wallet_rpc::amounts_list abd;
for (const auto& dst : ptx.dests)
abd.amounts.push_back(dst.amount);
fill(amounts_by_dest, abd);
// add spent key images
tools::wallet_rpc::key_image_list key_image_list;
bool all_are_txin_to_key = std::all_of(ptx.tx.vin.begin(), ptx.tx.vin.end(), [&](const cryptonote::txin_v& s_e) -> bool
@ -1092,7 +1086,7 @@ namespace tools
{
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
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, req.subtract_fee_from_outputs);
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())
{
@ -1109,7 +1103,7 @@ namespace tools
return false;
}
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.amounts_by_dest, res.fee, res.weight, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.weight, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, res.spent_key_images, er);
}
catch (const std::exception& e)
@ -1157,7 +1151,7 @@ namespace tools
return false;
}
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.amounts_by_dest_list, res.fee_list, res.weight_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.weight_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, res.spent_key_images_list, er);
}
catch (const std::exception& e)
@ -1546,7 +1540,7 @@ namespace tools
{
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.amounts_by_dest_list, res.fee_list, res.weight_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.weight_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, res.spent_key_images_list, er);
}
catch (const std::exception& e)
@ -1606,7 +1600,7 @@ namespace tools
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, req.outputs, mixin, req.unlock_time, priority, extra, req.account_index, subaddr_indices);
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.amounts_by_dest_list, res.fee_list, res.weight_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.weight_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, res.spent_key_images_list, er);
}
catch (const std::exception& e)
@ -1683,7 +1677,7 @@ namespace tools
return false;
}
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.amounts_by_dest, res.fee, res.weight, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.weight, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, res.spent_key_images, er);
}
catch (const std::exception& e)

@ -263,9 +263,9 @@ namespace tools
bool not_open(epee::json_rpc::error& er);
void handle_rpc_exception(const std::exception_ptr& e, epee::json_rpc::error& er, int default_error_code);
template<typename Ts, typename Tu, typename Tk, typename Ta>
template<typename Ts, typename Tu, typename Tk>
bool fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector,
bool get_tx_key, Ts& tx_key, Tu &amount, Ta &amounts_by_dest, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay,
bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, Tu &weight, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay,
Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, Tk &spent_key_images, epee::json_rpc::error &er);
bool validate_transfer(const std::list<wallet_rpc::transfer_destination>& destinations, const std::string& payment_id, std::vector<cryptonote::tx_destination_entry>& dsts, std::vector<uint8_t>& extra, bool at_least_one_destination, epee::json_rpc::error& er);

@ -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 27
#define WALLET_RPC_VERSION_MINOR 26
#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
@ -530,23 +530,11 @@ namespace wallet_rpc
END_KV_SERIALIZE_MAP()
};
struct amounts_list
{
std::list<uint64_t> amounts;
bool operator==(const amounts_list& other) const { return amounts == other.amounts; }
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amounts)
END_KV_SERIALIZE_MAP()
};
struct single_transfer_response
{
std::string tx_hash;
std::string tx_key;
uint64_t amount;
amounts_list amounts_by_dest;
uint64_t fee;
uint64_t weight;
std::string tx_blob;
@ -559,7 +547,6 @@ namespace wallet_rpc
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(tx_key)
KV_SERIALIZE(amount)
KV_SERIALIZE_OPT(amounts_by_dest, decltype(amounts_by_dest)())
KV_SERIALIZE(fee)
KV_SERIALIZE(weight)
KV_SERIALIZE(tx_blob)
@ -577,7 +564,6 @@ namespace wallet_rpc
std::list<transfer_destination> destinations;
uint32_t account_index;
std::set<uint32_t> subaddr_indices;
std::set<uint32_t> subtract_fee_from_outputs;
uint32_t priority;
uint64_t ring_size;
uint64_t unlock_time;
@ -591,7 +577,6 @@ namespace wallet_rpc
KV_SERIALIZE(destinations)
KV_SERIALIZE(account_index)
KV_SERIALIZE(subaddr_indices)
KV_SERIALIZE_OPT(subtract_fee_from_outputs, decltype(subtract_fee_from_outputs)())
KV_SERIALIZE(priority)
KV_SERIALIZE_OPT(ring_size, (uint64_t)0)
KV_SERIALIZE(unlock_time)
@ -613,7 +598,6 @@ namespace wallet_rpc
std::list<std::string> tx_hash_list;
std::list<std::string> tx_key_list;
std::list<uint64_t> amount_list;
std::list<amounts_list> amounts_by_dest_list;
std::list<uint64_t> fee_list;
std::list<uint64_t> weight_list;
std::list<std::string> tx_blob_list;
@ -626,7 +610,6 @@ namespace wallet_rpc
KV_SERIALIZE(tx_hash_list)
KV_SERIALIZE(tx_key_list)
KV_SERIALIZE(amount_list)
KV_SERIALIZE_OPT(amounts_by_dest_list, decltype(amounts_by_dest_list)())
KV_SERIALIZE(fee_list)
KV_SERIALIZE(weight_list)
KV_SERIALIZE(tx_blob_list)

@ -62,7 +62,6 @@ class TransferTest():
self.check_rescan()
self.check_is_key_image_spent()
self.check_scan_tx()
self.check_subtract_fee_from_outputs()
def reset(self):
print('Resetting blockchain')
@ -1047,85 +1046,5 @@ class TransferTest():
diff_transfers(receiver_wallet.get_transfers(), res)
assert receiver_wallet.get_balance().balance == expected_receiver_balance
def check_subtract_fee_from_outputs(self):
daemon = Daemon()
print('Testing fee-included transfers')
def inner_test_external_transfer(dsts, subtract_fee_from_outputs):
# refresh wallet and get balance
self.wallet[0].refresh()
balance1 = self.wallet[0].get_balance().balance
# Check that this transaction is possible with our current balance + other preconditions
dst_sum = sum(map(lambda x: x['amount'], dsts))
assert balance1 >= dst_sum
if subtract_fee_from_outputs:
assert max(subtract_fee_from_outputs) < len(dsts)
# transfer with subtractfeefrom=all
transfer_res = self.wallet[0].transfer(dsts, subtract_fee_from_outputs = subtract_fee_from_outputs, get_tx_metadata = True)
tx_hex = transfer_res.tx_metadata
tx_fee = transfer_res.fee
amount_spent = transfer_res.amount
amounts_by_dest = transfer_res.amounts_by_dest.amounts
# Assert that fee and amount spent to outputs adds up
assert tx_fee != 0
if subtract_fee_from_outputs:
assert tx_fee + amount_spent == dst_sum
else:
assert amount_spent == dst_sum
# Check the amounts by each destination that only the destinations set as subtractable
# got subtracted and that the subtracted dests are approximately correct
assert len(amounts_by_dest) == len(dsts) # if this fails... idk
for i in range(len(dsts)):
if i in subtract_fee_from_outputs: # dest is subtractable
approx_subtraction = tx_fee // len(subtract_fee_from_outputs)
assert amounts_by_dest[i] < dsts[i]['amount']
assert dsts[i]['amount'] - amounts_by_dest[i] - approx_subtraction <= 1
else:
assert amounts_by_dest[i] == dsts[i]['amount']
# relay tx and generate block (not to us, to simplify balance change calculations)
relay_res = self.wallet[0].relay_tx(tx_hex)
daemon.generateblocks('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 1)
# refresh and get balance again
self.wallet[0].refresh()
balance2 = self.wallet[0].get_balance().balance
# Check that the wallet balance dropped by the correct amount
balance_drop = balance1 - balance2
if subtract_fee_from_outputs:
assert balance_drop == dst_sum
else:
assert balance_drop == dst_sum + tx_fee
dst1 = {'address': '44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 'amount': 1100000000001}
dst2 = {'address': '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 'amount': 1200000000000}
dst3 = {'address': '46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 'amount': 1}
inner_test_external_transfer([dst1, dst2], [0, 1])
inner_test_external_transfer([dst1, dst2], [0])
inner_test_external_transfer([dst1, dst2], [1])
inner_test_external_transfer([dst1, dst2], [])
inner_test_external_transfer([dst1], [0])
inner_test_external_transfer([dst1], [])
inner_test_external_transfer([dst3], [])
try:
inner_test_external_transfer([dst1, dst3], [0, 1]) # Test subtractfeefrom if one of the outputs would underflow w/o good checks
raise ValueError('transfer request with tiny subtractable destination should have thrown')
except:
pass
# Check for JSONRPC error on bad index
try:
transfer_res = self.wallet[0].transfer([dst1], subtract_fee_from_outputs = [1])
raise ValueError('transfer request with index should have thrown')
except AssertionError:
pass
if __name__ == '__main__':
TransferTest().run_test()

@ -29,7 +29,6 @@
#include "gtest/gtest.h"
#include <cstdint>
#include "common/aligned.h"
TEST(aligned, large_null) { ASSERT_TRUE(aligned_malloc((size_t)-1, 1) == NULL); }

@ -1836,59 +1836,3 @@ TEST(parsing, unicode)
epee::misc_utils::parse::match_string2(si, s.end(), bs);
EXPECT_EQ(bs, "あまやかす");
}
TEST(parsing, strtoul)
{
long ul;
const char* p;
const char* endp;
errno = 0; // Some libc's only set errno on failure, some set it to 0 on success
p = "0";
endp = nullptr;
ul = std::strtoul(p, const_cast<char**>(&endp), 10);
EXPECT_EQ(0, errno);
EXPECT_EQ(0, ul);
EXPECT_EQ(p + 1, endp);
p = "000000";
endp = nullptr;
ul = std::strtoul(p, const_cast<char**>(&endp), 10);
EXPECT_EQ(0, errno);
EXPECT_EQ(0, ul);
EXPECT_EQ(p + 6, endp);
p = "1";
endp = nullptr;
ul = std::strtoul(p, const_cast<char**>(&endp), 10);
EXPECT_EQ(0, errno);
EXPECT_EQ(1, ul);
EXPECT_EQ(p + 1, endp);
p = "0q";
endp = nullptr;
ul = std::strtoul(p, const_cast<char**>(&endp), 10);
EXPECT_EQ(0, errno);
EXPECT_EQ(0, ul);
EXPECT_EQ(p + 1, endp);
p = " \t 0";
endp = nullptr;
ul = std::strtoul(p, const_cast<char**>(&endp), 10);
EXPECT_EQ(0, errno);
EXPECT_EQ(0, ul);
EXPECT_EQ(p + 9, endp);
p = "q";
endp = nullptr;
ul = std::strtoul(p, const_cast<char**>(&endp), 10);
EXPECT_EQ(0, ul);
EXPECT_EQ(p, endp);
p = "999999999999999999999999999999999999999";
endp = nullptr;
ul = std::strtoul(p, const_cast<char**>(&endp), 10);
EXPECT_EQ(ERANGE, errno);
EXPECT_EQ(ULLONG_MAX, ul);
}

@ -13,7 +13,6 @@
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "serialization/json_object.h"
#include "rpc/daemon_messages.h"
namespace test
@ -241,9 +240,3 @@ TEST(JsonSerialization, BulletproofTransaction)
EXPECT_EQ(tx_bytes, tx_copy_bytes);
}
TEST(JsonRpcSerialization, HandlerFromJson)
{
cryptonote::rpc::FullMessage req_full("{\"jsonrpc\":\"2.0\",\"method\":\"get_hashes_fast\",\"params\":[1]}", true);
cryptonote::rpc::GetHashesFast::Request request{};
EXPECT_THROW(request.fromJson(req_full.getMessage()), cryptonote::json::WRONG_TYPE);
}

@ -555,6 +555,8 @@ TEST(i2p_address, invalid)
EXPECT_TRUE(net::i2p_address::make(".b32.i2p:").has_error());
EXPECT_TRUE(net::i2p_address::make(b32_i2p + 1).has_error());
EXPECT_TRUE(net::i2p_address::make(boost::string_ref{b32_i2p, sizeof(b32_i2p) - 2}).has_error());
EXPECT_TRUE(net::i2p_address::make(std::string{b32_i2p} + ":65536").has_error());
EXPECT_TRUE(net::i2p_address::make(std::string{b32_i2p} + ":-1").has_error());
std::string i2p{b32_i2p};
i2p.at(10) = 1;
@ -568,7 +570,7 @@ TEST(i2p_address, unblockable_types)
ASSERT_NE(nullptr, i2p.host_str());
EXPECT_STREQ("<unknown i2p host>", i2p.host_str());
EXPECT_STREQ("<unknown i2p host>", i2p.str().c_str());
EXPECT_EQ(1u, i2p.port());
EXPECT_EQ(0u, i2p.port());
EXPECT_TRUE(i2p.is_unknown());
EXPECT_FALSE(i2p.is_local());
EXPECT_FALSE(i2p.is_loopback());
@ -579,7 +581,7 @@ TEST(i2p_address, unblockable_types)
ASSERT_NE(nullptr, i2p.host_str());
EXPECT_STREQ("<unknown i2p host>", i2p.host_str());
EXPECT_STREQ("<unknown i2p host>", i2p.str().c_str());
EXPECT_EQ(1u, i2p.port());
EXPECT_EQ(0u, i2p.port());
EXPECT_TRUE(i2p.is_unknown());
EXPECT_FALSE(i2p.is_local());
EXPECT_FALSE(i2p.is_loopback());
@ -594,14 +596,14 @@ TEST(i2p_address, valid)
const auto address1 = net::i2p_address::make(b32_i2p);
ASSERT_TRUE(address1.has_value());
EXPECT_EQ(1u, address1->port());
EXPECT_EQ(0u, address1->port());
EXPECT_STREQ(b32_i2p, address1->host_str());
EXPECT_STREQ(b32_i2p, address1->str().c_str());
EXPECT_TRUE(address1->is_blockable());
net::i2p_address address2{*address1};
EXPECT_EQ(1u, address2.port());
EXPECT_EQ(0u, address2.port());
EXPECT_STREQ(b32_i2p, address2.host_str());
EXPECT_STREQ(b32_i2p, address2.str().c_str());
EXPECT_TRUE(address2.is_blockable());
@ -618,9 +620,9 @@ TEST(i2p_address, valid)
address2 = MONERO_UNWRAP(net::i2p_address::make(std::string{b32_i2p_2} + ":6545"));
EXPECT_EQ(1u, address2.port());
EXPECT_EQ(6545, address2.port());
EXPECT_STREQ(b32_i2p_2, address2.host_str());
EXPECT_EQ(std::string{b32_i2p_2}, address2.str().c_str());
EXPECT_EQ(std::string{b32_i2p_2} + ":6545", address2.str().c_str());
EXPECT_TRUE(address2.is_blockable());
EXPECT_FALSE(address2.equal(*address1));
EXPECT_FALSE(address1->equal(address2));
@ -633,22 +635,22 @@ TEST(i2p_address, valid)
EXPECT_FALSE(address2.less(*address1));
EXPECT_TRUE(address1->less(address2));
net::i2p_address address3 = MONERO_UNWRAP(net::i2p_address::make(std::string{b32_i2p} + ":65535"));
net::i2p_address address3 = MONERO_UNWRAP(net::i2p_address::make(std::string{b32_i2p} + ":", 65535));
EXPECT_EQ(1u, address3.port());
EXPECT_EQ(65535, address3.port());
EXPECT_STREQ(b32_i2p, address3.host_str());
EXPECT_EQ(std::string{b32_i2p}, address3.str().c_str());
EXPECT_EQ(std::string{b32_i2p} + ":65535", address3.str().c_str());
EXPECT_TRUE(address3.is_blockable());
EXPECT_TRUE(address3.equal(*address1));
EXPECT_TRUE(address1->equal(address3));
EXPECT_TRUE(address3 == *address1);
EXPECT_TRUE(*address1 == address3);
EXPECT_FALSE(address3 != *address1);
EXPECT_FALSE(*address1 != address3);
EXPECT_FALSE(address3.equal(*address1));
EXPECT_FALSE(address1->equal(address3));
EXPECT_FALSE(address3 == *address1);
EXPECT_FALSE(*address1 == address3);
EXPECT_TRUE(address3 != *address1);
EXPECT_TRUE(*address1 != address3);
EXPECT_TRUE(address3.is_same_host(*address1));
EXPECT_TRUE(address1->is_same_host(address3));
EXPECT_FALSE(address3.less(*address1));
EXPECT_FALSE(address1->less(address3));
EXPECT_TRUE(address1->less(address3));
EXPECT_FALSE(address3.equal(address2));
EXPECT_FALSE(address2.equal(address3));
@ -664,8 +666,8 @@ TEST(i2p_address, valid)
TEST(i2p_address, generic_network_address)
{
const epee::net_utils::network_address i2p1{MONERO_UNWRAP(net::i2p_address::make(b32_i2p))};
const epee::net_utils::network_address i2p2{MONERO_UNWRAP(net::i2p_address::make(b32_i2p))};
const epee::net_utils::network_address i2p1{MONERO_UNWRAP(net::i2p_address::make(b32_i2p, 8080))};
const epee::net_utils::network_address i2p2{MONERO_UNWRAP(net::i2p_address::make(b32_i2p, 8080))};
const epee::net_utils::network_address ip{epee::net_utils::ipv4_network_address{100, 200}};
EXPECT_EQ(i2p1, i2p2);
@ -673,7 +675,7 @@ TEST(i2p_address, generic_network_address)
EXPECT_LT(ip, i2p1);
EXPECT_STREQ(b32_i2p, i2p1.host_str().c_str());
EXPECT_STREQ(b32_i2p, i2p1.str().c_str());
EXPECT_EQ(std::string{b32_i2p} + ":8080", i2p1.str());
EXPECT_EQ(epee::net_utils::address_type::i2p, i2p1.get_type_id());
EXPECT_EQ(epee::net_utils::address_type::i2p, i2p2.get_type_id());
EXPECT_EQ(epee::net_utils::address_type::ipv4, ip.get_type_id());
@ -701,11 +703,11 @@ TEST(i2p_address, epee_serializev_b32)
{
epee::byte_slice buffer{};
{
test_command_i2p command{MONERO_UNWRAP(net::i2p_address::make(b32_i2p))};
test_command_i2p command{MONERO_UNWRAP(net::i2p_address::make(b32_i2p, 10))};
EXPECT_FALSE(command.i2p.is_unknown());
EXPECT_NE(net::i2p_address{}, command.i2p);
EXPECT_STREQ(b32_i2p, command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
EXPECT_EQ(10u, command.i2p.port());
epee::serialization::portable_storage stg{};
EXPECT_TRUE(command.store(stg));
@ -717,7 +719,7 @@ TEST(i2p_address, epee_serializev_b32)
EXPECT_TRUE(command.i2p.is_unknown());
EXPECT_EQ(net::i2p_address{}, command.i2p);
EXPECT_STREQ(net::i2p_address::unknown_str(), command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
EXPECT_EQ(0u, command.i2p.port());
epee::serialization::portable_storage stg{};
EXPECT_TRUE(stg.load_from_binary(epee::to_span(buffer)));
@ -726,7 +728,7 @@ TEST(i2p_address, epee_serializev_b32)
EXPECT_FALSE(command.i2p.is_unknown());
EXPECT_NE(net::i2p_address{}, command.i2p);
EXPECT_STREQ(b32_i2p, command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
EXPECT_EQ(10u, command.i2p.port());
// make sure that exceeding max buffer doesn't destroy i2p_address::_load
{
@ -745,7 +747,7 @@ TEST(i2p_address, epee_serializev_b32)
EXPECT_TRUE(command.i2p.is_unknown());
EXPECT_EQ(net::i2p_address{}, command.i2p);
EXPECT_STRNE(b32_i2p, command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
EXPECT_EQ(0u, command.i2p.port());
}
TEST(i2p_address, epee_serialize_unknown)
@ -756,7 +758,7 @@ TEST(i2p_address, epee_serialize_unknown)
EXPECT_TRUE(command.i2p.is_unknown());
EXPECT_EQ(net::i2p_address{}, command.i2p);
EXPECT_STREQ(net::i2p_address::unknown_str(), command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
EXPECT_EQ(0u, command.i2p.port());
epee::serialization::portable_storage stg{};
EXPECT_TRUE(command.store(stg));
@ -768,7 +770,7 @@ TEST(i2p_address, epee_serialize_unknown)
EXPECT_TRUE(command.i2p.is_unknown());
EXPECT_EQ(net::i2p_address{}, command.i2p);
EXPECT_STRNE(b32_i2p, command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
EXPECT_EQ(0u, command.i2p.port());
epee::serialization::portable_storage stg{};
EXPECT_TRUE(stg.load_from_binary(epee::to_span(buffer)));
@ -777,7 +779,7 @@ TEST(i2p_address, epee_serialize_unknown)
EXPECT_TRUE(command.i2p.is_unknown());
EXPECT_EQ(net::i2p_address{}, command.i2p);
EXPECT_STREQ(net::i2p_address::unknown_str(), command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
EXPECT_EQ(0u, command.i2p.port());
// make sure that exceeding max buffer doesn't destroy i2p_address::_load
{
@ -796,18 +798,18 @@ TEST(i2p_address, epee_serialize_unknown)
EXPECT_TRUE(command.i2p.is_unknown());
EXPECT_EQ(net::i2p_address{}, command.i2p);
EXPECT_STRNE(b32_i2p, command.i2p.host_str());
EXPECT_EQ(1u, command.i2p.port());
EXPECT_EQ(0u, command.i2p.port());
}
TEST(i2p_address, boost_serialize_b32)
{
std::string buffer{};
{
const net::i2p_address i2p = MONERO_UNWRAP(net::i2p_address::make(b32_i2p));
const net::i2p_address i2p = MONERO_UNWRAP(net::i2p_address::make(b32_i2p, 10));
EXPECT_FALSE(i2p.is_unknown());
EXPECT_NE(net::i2p_address{}, i2p);
EXPECT_STREQ(b32_i2p, i2p.host_str());
EXPECT_EQ(1u, i2p.port());
EXPECT_EQ(10u, i2p.port());
std::ostringstream stream{};
{
@ -822,7 +824,7 @@ TEST(i2p_address, boost_serialize_b32)
EXPECT_TRUE(i2p.is_unknown());
EXPECT_EQ(net::i2p_address{}, i2p);
EXPECT_STREQ(net::i2p_address::unknown_str(), i2p.host_str());
EXPECT_EQ(1u, i2p.port());
EXPECT_EQ(0u, i2p.port());
std::istringstream stream{buffer};
boost::archive::portable_binary_iarchive archive{stream};
@ -831,7 +833,7 @@ TEST(i2p_address, boost_serialize_b32)
EXPECT_FALSE(i2p.is_unknown());
EXPECT_NE(net::i2p_address{}, i2p);
EXPECT_STREQ(b32_i2p, i2p.host_str());
EXPECT_EQ(1u, i2p.port());
EXPECT_EQ(10u, i2p.port());
}
TEST(i2p_address, boost_serialize_unknown)
@ -842,7 +844,7 @@ TEST(i2p_address, boost_serialize_unknown)
EXPECT_TRUE(i2p.is_unknown());
EXPECT_EQ(net::i2p_address::unknown(), i2p);
EXPECT_STREQ(net::i2p_address::unknown_str(), i2p.host_str());
EXPECT_EQ(1u, i2p.port());
EXPECT_EQ(0u, i2p.port());
std::ostringstream stream{};
{
@ -857,7 +859,7 @@ TEST(i2p_address, boost_serialize_unknown)
EXPECT_TRUE(i2p.is_unknown());
EXPECT_EQ(net::i2p_address{}, i2p);
EXPECT_STREQ(net::i2p_address::unknown_str(), i2p.host_str());
EXPECT_EQ(1u, i2p.port());
EXPECT_EQ(0u, i2p.port());
std::istringstream stream{buffer};
boost::archive::portable_binary_iarchive archive{stream};
@ -866,7 +868,7 @@ TEST(i2p_address, boost_serialize_unknown)
EXPECT_TRUE(i2p.is_unknown());
EXPECT_EQ(net::i2p_address::unknown(), i2p);
EXPECT_STREQ(net::i2p_address::unknown_str(), i2p.host_str());
EXPECT_EQ(1u, i2p.port());
EXPECT_EQ(0u, i2p.port());
}
TEST(get_network_address, i2p)
@ -882,13 +884,16 @@ TEST(get_network_address, i2p)
ASSERT_TRUE(bool(address));
EXPECT_EQ(epee::net_utils::address_type::i2p, address->get_type_id());
EXPECT_STREQ(b32_i2p, address->host_str().c_str());
EXPECT_EQ(std::string{b32_i2p}, address->str());
EXPECT_EQ(std::string{b32_i2p} + ":1000", address->str());
address = net::get_network_address(std::string{b32_i2p} + ":2000", 1000);
ASSERT_TRUE(bool(address));
EXPECT_EQ(epee::net_utils::address_type::i2p, address->get_type_id());
EXPECT_STREQ(b32_i2p, address->host_str().c_str());
EXPECT_EQ(std::string{b32_i2p}, address->str());
EXPECT_EQ(std::string{b32_i2p} + ":2000", address->str());
address = net::get_network_address(std::string{b32_i2p} + ":65536", 1000);
EXPECT_EQ(net::error::invalid_port, address);
}
TEST(get_network_address, ipv4)

@ -59,7 +59,9 @@ struct Struct
};
template <class Archive>
static bool do_serialize(Archive &ar, Struct &s) {
struct serializer<Archive, Struct>
{
static bool serialize(Archive &ar, Struct &s) {
ar.begin_object();
ar.tag("a");
ar.serialize_int(s.a);
@ -69,7 +71,8 @@ static bool do_serialize(Archive &ar, Struct &s) {
ar.serialize_blob(s.blob, sizeof(s.blob));
ar.end_object();
return true;
}
}
};
struct Struct1
{
@ -119,23 +122,6 @@ bool try_parse(const string &blob)
return serialization::parse_binary(blob, s1);
}
namespace example_namespace
{
struct ADLExampleStruct
{
std::string msg;
};
template <class Archive>
static bool do_serialize(Archive &ar, ADLExampleStruct &aes)
{
ar.begin_object();
FIELD_N("custom_fieldname", aes.msg);
ar.end_object();
return ar.good();
}
}
TEST(Serialization, BinaryArchiveInts) {
uint64_t x = 0xff00000000, x1;
@ -1192,18 +1178,3 @@ TEST(Serialization, difficulty_type)
ASSERT_EQ(v_original, v_unserialized);
}
TEST(Serialization, adl_free_function)
{
std::stringstream ss;
json_archive<true> ar(ss);
const std::string msg = "Howdy, World!";
example_namespace::ADLExampleStruct aes{msg};
ASSERT_TRUE(serialization::serialize(ar, aes));
// VVVVVVVVVVVVVVVVVVVVVVVVVV weird string serialization artifact
const std::string expected = "{\"custom_fieldname\": " + std::to_string(msg.size()) + '"' + epee::string_tools::buff_to_hex_nodelimer(msg) + "\"}";
EXPECT_EQ(expected, ss.str());
}

@ -38,14 +38,13 @@ class Wallet(object):
self.port = port
self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else 18090+idx))
def transfer(self, destinations, account_index = 0, subaddr_indices = [], priority = 0, ring_size = 0, unlock_time = 0, payment_id = '', get_tx_key = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False, subtract_fee_from_outputs = []):
def transfer(self, destinations, account_index = 0, subaddr_indices = [], priority = 0, ring_size = 0, unlock_time = 0, payment_id = '', get_tx_key = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False):
transfer = {
'method': 'transfer',
'params': {
'destinations': destinations,
'account_index': account_index,
'subaddr_indices': subaddr_indices,
'subtract_fee_from_outputs': subtract_fee_from_outputs,
'priority': priority,
'ring_size' : ring_size,
'unlock_time' : unlock_time,

Loading…
Cancel
Save