aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--README.md10
-rw-r--r--contrib/depends/packages/packages.mk2
-rw-r--r--contrib/epee/include/int-util.h42
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl2
-rw-r--r--contrib/epee/include/net/local_ip.h7
-rw-r--r--contrib/epee/include/net/net_utils_base.h16
-rw-r--r--contrib/epee/include/storages/portable_storage_bin_utils.h46
-rw-r--r--contrib/epee/include/storages/portable_storage_from_bin.h4
-rw-r--r--contrib/epee/include/storages/portable_storage_to_bin.h12
-rw-r--r--external/boost/archive/portable_binary_iarchive.hpp4
-rw-r--r--external/boost/archive/portable_binary_oarchive.hpp2
-rw-r--r--external/db_drivers/liblmdb/mdb_dump.c2
-rw-r--r--external/db_drivers/liblmdb/mdb_load.c4
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_blackball.cpp177
-rw-r--r--src/crypto/slow-hash.c6
-rw-r--r--src/cryptonote_basic/difficulty.h1
-rw-r--r--src/cryptonote_config.h3
-rw-r--r--src/cryptonote_core/blockchain.cpp54
-rw-r--r--src/cryptonote_core/blockchain.h3
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp8
-rw-r--r--src/daemon/command_parser_executor.cpp28
-rw-r--r--src/daemon/command_parser_executor.h2
-rw-r--r--src/daemon/command_server.cpp7
-rw-r--r--src/daemon/rpc_command_executor.cpp53
-rw-r--r--src/daemon/rpc_command_executor.h7
-rw-r--r--src/device/device_ledger.cpp2
-rw-r--r--src/p2p/net_node.h3
-rw-r--r--src/p2p/net_node.inl53
-rw-r--r--src/p2p/net_peerlist_boost_serialization.h2
-rw-r--r--src/rpc/core_rpc_server.cpp4
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h50
-rw-r--r--src/simplewallet/simplewallet.cpp73
-rw-r--r--src/wallet/api/subaddress_account.cpp4
-rw-r--r--src/wallet/api/wallet.cpp4
-rw-r--r--src/wallet/ringdb.cpp2
-rw-r--r--src/wallet/wallet2.cpp102
-rw-r--r--src/wallet/wallet2.h16
-rw-r--r--src/wallet/wallet_light_rpc.h47
-rw-r--r--src/wallet/wallet_rpc_server.cpp24
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h10
-rw-r--r--tests/core_tests/block_validation.cpp15
-rw-r--r--tests/core_tests/block_validation.h12
-rw-r--r--tests/core_tests/chaingen_main.cpp1
-rw-r--r--tests/functional_tests/transactions_flow_test.cpp8
-rw-r--r--tests/performance_tests/check_hash.h14
-rw-r--r--tests/unit_tests/difficulty.cpp14
-rw-r--r--tests/unit_tests/epee_levin_protocol_handler_async.cpp46
-rw-r--r--tests/unit_tests/net.cpp18
-rw-r--r--tests/unit_tests/output_distribution.cpp2
-rw-r--r--utils/python-rpc/framework/wallet.py3
52 files changed, 779 insertions, 255 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 03d57785c..d5bf7af62 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,6 +34,7 @@ include(CheckCXXCompilerFlag)
include(CheckLinkerFlag)
include(CheckLibraryExists)
include(CheckFunctionExists)
+include(FindPythonInterp)
if (IOS)
INCLUDE(CmakeLists_IOS.txt)
diff --git a/README.md b/README.md
index 8f4d1292f..0f977ca2e 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,9 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers.
- [Release staging schedule and protocol](#release-staging-schedule-and-protocol)
- [Compiling Monero from source](#compiling-monero-from-source)
- [Dependencies](#dependencies)
+ - [Internationalization](#Internationalization)
+ - [Using Tor](#Using Tor)
+ - [Debugging](#Debugging)
- [Known issues](#known-issues)
## Development resources
@@ -550,13 +553,12 @@ The produced binaries still link libc dynamically. If the binary is compiled on
Packages are available for
-* Ubuntu and [snap supported](https://snapcraft.io/docs/core/install) systems, via a community contributed build.
+* Debian Bullseye and Sid
```bash
- snap install monero --beta
+ sudo apt install monero
```
-
-Installing a snap is very quick. Snaps are secure. They are isolated with all of their dependencies. Snaps also auto update when a new version is released.
+More info and versions in the [Debian package tracker](https://tracker.debian.org/pkg/monero).
* Arch Linux (via [AUR](https://aur.archlinux.org/)):
- Stable release: [`monero`](https://aur.archlinux.org/packages/monero)
diff --git a/contrib/depends/packages/packages.mk b/contrib/depends/packages/packages.mk
index 1e5a74670..f4b9c6407 100644
--- a/contrib/depends/packages/packages.mk
+++ b/contrib/depends/packages/packages.mk
@@ -12,7 +12,7 @@ packages += gtest
endif
ifneq ($(host_arch),riscv64)
- packages += unwind
+linux_packages += unwind
endif
ifeq ($(host_os),mingw32)
diff --git a/contrib/epee/include/int-util.h b/contrib/epee/include/int-util.h
index 0ed6505ff..8ef5be40a 100644
--- a/contrib/epee/include/int-util.h
+++ b/contrib/epee/include/int-util.h
@@ -129,9 +129,12 @@ static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uin
return remainder;
}
+#define IDENT16(x) ((uint16_t) (x))
#define IDENT32(x) ((uint32_t) (x))
#define IDENT64(x) ((uint64_t) (x))
+#define SWAP16(x) ((((uint16_t) (x) & 0x00ff) << 8) | \
+ (((uint16_t) (x) & 0xff00) >> 8))
#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \
(((uint32_t) (x) & 0x0000ff00) << 8) | \
(((uint32_t) (x) & 0x00ff0000) >> 8) | \
@@ -145,10 +148,18 @@ static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uin
(((uint64_t) (x) & 0x00ff000000000000) >> 40) | \
(((uint64_t) (x) & 0xff00000000000000) >> 56))
+static inline uint16_t ident16(uint16_t x) { return x; }
static inline uint32_t ident32(uint32_t x) { return x; }
static inline uint64_t ident64(uint64_t x) { return x; }
#ifndef __OpenBSD__
+# if defined(__ANDROID__) && defined(__swap16) && !defined(swap16)
+# define swap16 __swap16
+# elif !defined(swap16)
+static inline uint16_t swap16(uint16_t x) {
+ return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
+}
+# endif
# if defined(__ANDROID__) && defined(__swap32) && !defined(swap32)
# define swap32 __swap32
# elif !defined(swap32)
@@ -176,6 +187,12 @@ static inline uint64_t swap64(uint64_t x) {
static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { }
#undef UNUSED
+static inline void mem_inplace_swap16(void *mem, size_t n) {
+ size_t i;
+ for (i = 0; i < n; i++) {
+ ((uint16_t *) mem)[i] = swap16(((const uint16_t *) mem)[i]);
+ }
+}
static inline void mem_inplace_swap32(void *mem, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
@@ -189,6 +206,9 @@ static inline void mem_inplace_swap64(void *mem, size_t n) {
}
}
+static inline void memcpy_ident16(void *dst, const void *src, size_t n) {
+ memcpy(dst, src, 2 * n);
+}
static inline void memcpy_ident32(void *dst, const void *src, size_t n) {
memcpy(dst, src, 4 * n);
}
@@ -196,6 +216,12 @@ static inline void memcpy_ident64(void *dst, const void *src, size_t n) {
memcpy(dst, src, 8 * n);
}
+static inline void memcpy_swap16(void *dst, const void *src, size_t n) {
+ size_t i;
+ for (i = 0; i < n; i++) {
+ ((uint16_t *) dst)[i] = swap16(((const uint16_t *) src)[i]);
+ }
+}
static inline void memcpy_swap32(void *dst, const void *src, size_t n) {
size_t i;
for (i = 0; i < n; i++) {
@@ -220,6 +246,14 @@ static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not e
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
+#define SWAP16LE IDENT16
+#define SWAP16BE SWAP16
+#define swap16le ident16
+#define swap16be swap16
+#define mem_inplace_swap16le mem_inplace_ident
+#define mem_inplace_swap16be mem_inplace_swap16
+#define memcpy_swap16le memcpy_ident16
+#define memcpy_swap16be memcpy_swap16
#define SWAP32LE IDENT32
#define SWAP32BE SWAP32
#define swap32le ident32
@@ -239,6 +273,14 @@ static_assert(false, "BYTE_ORDER is undefined. Perhaps, GNU extensions are not e
#endif
#if BYTE_ORDER == BIG_ENDIAN
+#define SWAP16BE IDENT16
+#define SWAP16LE SWAP16
+#define swap16be ident16
+#define swap16le swap16
+#define mem_inplace_swap16be mem_inplace_ident
+#define mem_inplace_swap16le mem_inplace_swap16
+#define memcpy_swap16be memcpy_ident16
+#define memcpy_swap16le memcpy_swap16
#define SWAP32BE IDENT32
#define SWAP32LE SWAP32
#define swap32be ident32
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 12a87071a..8d96e4a84 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -154,7 +154,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
}
else
{
- const auto ip_{remote_ep.address().to_v6()};
+ const auto ip_ = remote_ep.address().to_v6();
return start(is_income, is_multithreaded, ipv6_network_address{ip_, remote_ep.port()});
}
CATCH_ENTRY_L0("connection<t_protocol_handler>::start()", false);
diff --git a/contrib/epee/include/net/local_ip.h b/contrib/epee/include/net/local_ip.h
index ce74e1cd3..246cf6ad8 100644
--- a/contrib/epee/include/net/local_ip.h
+++ b/contrib/epee/include/net/local_ip.h
@@ -30,6 +30,11 @@
#include <string>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/asio/ip/address_v6.hpp>
+#include "int-util.h"
+
+// IP addresses are kept in network byte order
+// Masks below are little endian
+// -> convert from network byte order to host byte order before comparing
namespace epee
{
@@ -62,6 +67,7 @@ namespace epee
inline
bool is_ip_local(uint32_t ip)
{
+ ip = SWAP32LE(ip);
/*
local ip area
10.0.0.0 — 10.255.255.255
@@ -85,6 +91,7 @@ namespace epee
inline
bool is_ip_loopback(uint32_t ip)
{
+ ip = SWAP32LE(ip);
if( (ip | 0xffffff00) == 0xffffff7f)
return true;
//MAKE_IP
diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h
index dd80fae8b..028e605d7 100644
--- a/contrib/epee/include/net/net_utils_base.h
+++ b/contrib/epee/include/net/net_utils_base.h
@@ -38,6 +38,7 @@
#include "enums.h"
#include "misc_log_ex.h"
#include "serialization/keyvalue_serialization.h"
+#include "int-util.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net"
@@ -91,7 +92,20 @@ namespace net_utils
static constexpr bool is_blockable() noexcept { return true; }
BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(m_ip)
+ if (is_store)
+ {
+ KV_SERIALIZE_VAL_POD_AS_BLOB_N(m_ip, "ip")
+ uint32_t ip = SWAP32LE(this_ref.m_ip);
+ epee::serialization::selector<is_store>::serialize(ip, stg, hparent_section, "m_ip");
+ }
+ else
+ {
+ if (!epee::serialization::selector<is_store>::serialize_t_val_as_blob(this_ref.m_ip, stg, hparent_section, "ip"))
+ {
+ KV_SERIALIZE(m_ip)
+ const_cast<ipv4_network_address&>(this_ref).m_ip = SWAP32LE(this_ref.m_ip);
+ }
+ }
KV_SERIALIZE(m_port)
END_KV_SERIALIZE_MAP()
};
diff --git a/contrib/epee/include/storages/portable_storage_bin_utils.h b/contrib/epee/include/storages/portable_storage_bin_utils.h
new file mode 100644
index 000000000..bcde64487
--- /dev/null
+++ b/contrib/epee/include/storages/portable_storage_bin_utils.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include "int-util.h"
+
+template<typename T> T convert_swapper(T t) { return t; }
+template<> inline uint16_t convert_swapper(uint16_t t) { return SWAP16LE(t); }
+template<> inline int16_t convert_swapper(int16_t t) { return SWAP16LE((uint16_t&)t); }
+template<> inline uint32_t convert_swapper(uint32_t t) { return SWAP32LE(t); }
+template<> inline int32_t convert_swapper(int32_t t) { return SWAP32LE((uint32_t&)t); }
+template<> inline uint64_t convert_swapper(uint64_t t) { return SWAP64LE(t); }
+template<> inline int64_t convert_swapper(int64_t t) { return SWAP64LE((uint64_t&)t); }
+template<> inline double convert_swapper(double t) { union { uint64_t u; double d; } u; u.d = t; u.u = SWAP64LE(u.u); return u.d; }
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define CONVERT_POD(x) convert_swapper(x)
+#else
+#define CONVERT_POD(x) (x)
+#endif
diff --git a/contrib/epee/include/storages/portable_storage_from_bin.h b/contrib/epee/include/storages/portable_storage_from_bin.h
index e0a32b3ca..c0b6cc7b1 100644
--- a/contrib/epee/include/storages/portable_storage_from_bin.h
+++ b/contrib/epee/include/storages/portable_storage_from_bin.h
@@ -30,6 +30,7 @@
#include "misc_language.h"
#include "portable_storage_base.h"
+#include "portable_storage_bin_utils.h"
#ifdef EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
@@ -117,6 +118,7 @@ namespace epee
RECURSION_LIMITATION();
static_assert(std::is_pod<t_pod_type>::value, "POD type expected");
read(&pod_val, sizeof(pod_val));
+ pod_val = CONVERT_POD(pod_val);
}
template<class t_type>
@@ -140,7 +142,7 @@ namespace epee
sa.reserve(size);
//TODO: add some optimization here later
while(size--)
- sa.m_array.push_back(read<type_name>());
+ sa.m_array.push_back(read<type_name>());
return storage_entry(array_entry(sa));
}
diff --git a/contrib/epee/include/storages/portable_storage_to_bin.h b/contrib/epee/include/storages/portable_storage_to_bin.h
index 9501bbc2a..137497e19 100644
--- a/contrib/epee/include/storages/portable_storage_to_bin.h
+++ b/contrib/epee/include/storages/portable_storage_to_bin.h
@@ -31,6 +31,7 @@
#include "pragma_comp_defs.h"
#include "misc_language.h"
#include "portable_storage_base.h"
+#include "portable_storage_bin_utils.h"
namespace epee
{
@@ -40,8 +41,9 @@ namespace epee
template<class pack_value, class t_stream>
size_t pack_varint_t(t_stream& strm, uint8_t type_or, size_t& pv)
{
- pack_value v = (*((pack_value*)&pv)) << 2;
+ pack_value v = pv << 2;
v |= type_or;
+ v = CONVERT_POD(v);
strm.write((const char*)&v, sizeof(pack_value));
return sizeof(pack_value);
}
@@ -93,8 +95,11 @@ namespace epee
uint8_t type = contained_type|SERIALIZE_FLAG_ARRAY;
m_strm.write((const char*)&type, 1);
pack_varint(m_strm, arr_pod.m_array.size());
- for(const t_pod_type& x: arr_pod.m_array)
+ for(t_pod_type x: arr_pod.m_array)
+ {
+ x = CONVERT_POD(x);
m_strm.write((const char*)&x, sizeof(t_pod_type));
+ }
return true;
}
@@ -147,7 +152,8 @@ namespace epee
bool pack_pod_type(uint8_t type, const pod_type& v)
{
m_strm.write((const char*)&type, 1);
- m_strm.write((const char*)&v, sizeof(pod_type));
+ pod_type v0 = CONVERT_POD(v);
+ m_strm.write((const char*)&v0, sizeof(pod_type));
return true;
}
//section, array_entry
diff --git a/external/boost/archive/portable_binary_iarchive.hpp b/external/boost/archive/portable_binary_iarchive.hpp
index bd19599f3..d17e95c05 100644
--- a/external/boost/archive/portable_binary_iarchive.hpp
+++ b/external/boost/archive/portable_binary_iarchive.hpp
@@ -258,7 +258,7 @@ portable_binary_iarchive::load_impl(boost::intmax_t & l, char maxsize){
this->primitive_base_t::load_binary(cptr, size);
#if BOOST_ENDIAN_BIG_BYTE
- if(m_flags & endian_little)
+ if((m_flags & endian_little) || (!(m_flags & endian_big)))
#else
if(m_flags & endian_big)
#endif
@@ -343,6 +343,8 @@ portable_binary_iarchive::init(unsigned int flags){
);
#endif
}
+ if (!(m_flags & (endian_little | endian_big)))
+ m_flags |= endian_little;
unsigned char x;
load(x);
m_flags = x << CHAR_BIT;
diff --git a/external/boost/archive/portable_binary_oarchive.hpp b/external/boost/archive/portable_binary_oarchive.hpp
index 783c7f7c9..a0ac0a9b5 100644
--- a/external/boost/archive/portable_binary_oarchive.hpp
+++ b/external/boost/archive/portable_binary_oarchive.hpp
@@ -171,7 +171,7 @@ protected:
void init(unsigned int flags);
public:
- portable_binary_oarchive(std::ostream & os, unsigned flags = 0) :
+ portable_binary_oarchive(std::ostream & os, unsigned flags = endian_little) :
primitive_base_t(
* os.rdbuf(),
0 != (flags & boost::archive::no_codecvt)
diff --git a/external/db_drivers/liblmdb/mdb_dump.c b/external/db_drivers/liblmdb/mdb_dump.c
index b7737f12d..068dab5a8 100644
--- a/external/db_drivers/liblmdb/mdb_dump.c
+++ b/external/db_drivers/liblmdb/mdb_dump.c
@@ -64,6 +64,8 @@ static void text(MDB_val *v)
end = c + v->mv_size;
while (c < end) {
if (isprint(*c)) {
+ if (*c == '\\')
+ putchar('\\');
putchar(*c);
} else {
putchar('\\');
diff --git a/external/db_drivers/liblmdb/mdb_load.c b/external/db_drivers/liblmdb/mdb_load.c
index ad911c088..e900ae660 100644
--- a/external/db_drivers/liblmdb/mdb_load.c
+++ b/external/db_drivers/liblmdb/mdb_load.c
@@ -236,7 +236,7 @@ badend:
while (c2 < end) {
if (*c2 == '\\') {
if (c2[1] == '\\') {
- c1++; c2 += 2;
+ *c1++ = *c2;
} else {
if (c2+3 > end || !isxdigit(c2[1]) || !isxdigit(c2[2])) {
Eof = 1;
@@ -244,8 +244,8 @@ badend:
return EOF;
}
*c1++ = unhex(++c2);
- c2 += 2;
}
+ c2 += 2;
} else {
/* copies are redundant when no escapes were used */
*c1++ = *c2++;
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 1ede7af62..760e380a9 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -595,7 +595,7 @@ bool BlockchainLMDB::need_resize(uint64_t threshold_size) const
MDEBUG("Space remaining: " << mei.me_mapsize - size_used);
MDEBUG("Size threshold: " << threshold_size);
float resize_percent = RESIZE_PERCENT;
- MDEBUG(boost::format("Percent used: %.04f Percent threshold: %.04f") % ((double)size_used/mei.me_mapsize) % resize_percent);
+ MDEBUG(boost::format("Percent used: %.04f Percent threshold: %.04f") % (100.*size_used/mei.me_mapsize) % (100.*resize_percent));
if (threshold_size > 0)
{
diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp
index f824d93a6..857e97afd 100644
--- a/src/blockchain_utilities/blockchain_blackball.cpp
+++ b/src/blockchain_utilities/blockchain_blackball.cpp
@@ -415,6 +415,115 @@ static bool for_all_transactions(const std::string &filename, uint64_t &start_id
return fret;
}
+static bool for_all_transactions(const std::string &filename, const uint64_t &start_idx, uint64_t &n_txes, const std::function<bool(bool, uint64_t, const cryptonote::transaction_prefix&)> &f)
+{
+ MDB_env *env;
+ MDB_dbi dbi_blocks, dbi_txs;
+ MDB_txn *txn;
+ MDB_cursor *cur_blocks, *cur_txs;
+ int dbr;
+ bool tx_active = false;
+ MDB_val k;
+ MDB_val v;
+
+ dbr = mdb_env_create(&env);
+ if (dbr) throw std::runtime_error("Failed to create LDMB environment: " + std::string(mdb_strerror(dbr)));
+ dbr = mdb_env_set_maxdbs(env, 3);
+ if (dbr) throw std::runtime_error("Failed to set max env dbs: " + std::string(mdb_strerror(dbr)));
+ const std::string actual_filename = filename;
+ dbr = mdb_env_open(env, actual_filename.c_str(), 0, 0664);
+ if (dbr) throw std::runtime_error("Failed to open rings database file '"
+ + actual_filename + "': " + std::string(mdb_strerror(dbr)));
+
+ dbr = mdb_txn_begin(env, NULL, MDB_RDONLY, &txn);
+ if (dbr) throw std::runtime_error("Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr)));
+ epee::misc_utils::auto_scope_leave_caller txn_dtor = epee::misc_utils::create_scope_leave_handler([&](){if (tx_active) mdb_txn_abort(txn);});
+ tx_active = true;
+
+ dbr = mdb_dbi_open(txn, "blocks", MDB_INTEGERKEY, &dbi_blocks);
+ if (dbr) throw std::runtime_error("Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr)));
+ dbr = mdb_dbi_open(txn, "txs_pruned", MDB_INTEGERKEY, &dbi_txs);
+ if (dbr) throw std::runtime_error("Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr)));
+
+ dbr = mdb_cursor_open(txn, dbi_blocks, &cur_blocks);
+ if (dbr) throw std::runtime_error("Failed to create LMDB cursor: " + std::string(mdb_strerror(dbr)));
+ dbr = mdb_cursor_open(txn, dbi_txs, &cur_txs);
+ if (dbr) throw std::runtime_error("Failed to create LMDB cursor: " + std::string(mdb_strerror(dbr)));
+
+ MDB_stat stat;
+ dbr = mdb_stat(txn, dbi_blocks, &stat);
+ if (dbr) throw std::runtime_error("Failed to query txs stat: " + std::string(mdb_strerror(dbr)));
+ uint64_t n_blocks = stat.ms_entries;
+ dbr = mdb_stat(txn, dbi_txs, &stat);
+ if (dbr) throw std::runtime_error("Failed to query txs stat: " + std::string(mdb_strerror(dbr)));
+ n_txes = stat.ms_entries;
+
+ bool fret = true;
+
+ MDB_cursor_op op_blocks = MDB_FIRST;
+ MDB_cursor_op op_txs = MDB_FIRST;
+ uint64_t tx_idx = 0;
+ while (1)
+ {
+ int ret = mdb_cursor_get(cur_blocks, &k, &v, op_blocks);
+ op_blocks = MDB_NEXT;
+ if (ret == MDB_NOTFOUND)
+ break;
+ if (ret)
+ throw std::runtime_error("Failed to enumerate blocks: " + std::string(mdb_strerror(ret)));
+
+ if (k.mv_size != sizeof(uint64_t))
+ throw std::runtime_error("Bad key size");
+ uint64_t height = *(const uint64_t*)k.mv_data;
+ blobdata bd;
+ bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
+ block b;
+ if (!parse_and_validate_block_from_blob(bd, b))
+ throw std::runtime_error("Failed to parse block from blob retrieved from the db");
+
+ ret = mdb_cursor_get(cur_txs, &k, &v, op_txs);
+ if (ret)
+ throw std::runtime_error("Failed to fetch transaction " + string_tools::pod_to_hex(get_transaction_hash(b.miner_tx)) + ": " + std::string(mdb_strerror(ret)));
+ op_txs = MDB_NEXT;
+
+ bool last_block = height == n_blocks - 1;
+ if (start_idx <= tx_idx++ && !f(last_block && b.tx_hashes.empty(), height, b.miner_tx))
+ {
+ fret = false;
+ break;
+ }
+ for (size_t i = 0; i < b.tx_hashes.size(); ++i)
+ {
+ const crypto::hash& txid = b.tx_hashes[i];
+ ret = mdb_cursor_get(cur_txs, &k, &v, op_txs);
+ if (ret)
+ throw std::runtime_error("Failed to fetch transaction " + string_tools::pod_to_hex(txid) + ": " + std::string(mdb_strerror(ret)));
+ if (start_idx <= tx_idx++)
+ {
+ cryptonote::transaction_prefix tx;
+ bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
+ CHECK_AND_ASSERT_MES(parse_and_validate_tx_prefix_from_blob(bd, tx), false, "Failed to parse transaction from blob");
+ if (!f(last_block && i == b.tx_hashes.size() - 1, height, tx))
+ {
+ fret = false;
+ break;
+ }
+ }
+ }
+ if (!fret)
+ break;
+ }
+
+ mdb_cursor_close(cur_blocks);
+ mdb_cursor_close(cur_txs);
+ mdb_txn_commit(txn);
+ tx_active = false;
+ mdb_dbi_close(env, dbi_blocks);
+ mdb_dbi_close(env, dbi_txs);
+ mdb_env_close(env);
+ return fret;
+}
+
static uint64_t find_first_diverging_transaction(const std::string &first_filename, const std::string &second_filename)
{
MDB_env *env[2];
@@ -1094,6 +1203,7 @@ int main(int argc, char* argv[])
const command_line::arg_descriptor<std::string> arg_extra_spent_list = {"extra-spent-list", "Optional list of known spent outputs",""};
const command_line::arg_descriptor<std::string> arg_export = {"export", "Filename to export the backball list to"};
const command_line::arg_descriptor<bool> arg_force_chain_reaction_pass = {"force-chain-reaction-pass", "Run the chain reaction pass even if no new blockchain data was processed"};
+ const command_line::arg_descriptor<bool> arg_historical_stat = {"historical-stat", "Report historical stat of spent outputs for every 10000 blocks window"};
command_line::add_arg(desc_cmd_sett, arg_blackball_db_dir);
command_line::add_arg(desc_cmd_sett, arg_log_level);
@@ -1105,6 +1215,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, arg_extra_spent_list);
command_line::add_arg(desc_cmd_sett, arg_export);
command_line::add_arg(desc_cmd_sett, arg_force_chain_reaction_pass);
+ command_line::add_arg(desc_cmd_sett, arg_historical_stat);
command_line::add_arg(desc_cmd_sett, arg_inputs);
command_line::add_arg(desc_cmd_only, command_line::arg_help);
@@ -1145,6 +1256,7 @@ int main(int argc, char* argv[])
bool opt_check_subsets = command_line::get_arg(vm, arg_check_subsets);
bool opt_verbose = command_line::get_arg(vm, arg_verbose);
bool opt_force_chain_reaction_pass = command_line::get_arg(vm, arg_force_chain_reaction_pass);
+ bool opt_historical_stat = command_line::get_arg(vm, arg_historical_stat);
std::string opt_export = command_line::get_arg(vm, arg_export);
std::string extra_spent_list = command_line::get_arg(vm, arg_extra_spent_list);
std::vector<std::pair<uint64_t, uint64_t>> extra_spent_outputs = extra_spent_list.empty() ? std::vector<std::pair<uint64_t, uint64_t>>() : load_outputs(extra_spent_list);
@@ -1196,6 +1308,69 @@ int main(int argc, char* argv[])
MDB_cursor *cur0;
open_db(inputs[0], &env0, &txn0, &cur0, &dbi0);
+ std::vector<output_data> work_spent;
+
+ if (opt_historical_stat)
+ {
+ if (!start_blackballed_outputs)
+ {
+ MINFO("Spent outputs database is empty. Either you haven't run the analysis mode yet, or there is really no output marked as spent.");
+ goto skip_secondary_passes;
+ }
+ MDB_txn *txn;
+ int dbr = mdb_txn_begin(env, NULL, 0, &txn);
+ CHECK_AND_ASSERT_THROW_MES(!dbr, "Failed to create LMDB transaction: " + std::string(mdb_strerror(dbr)));
+ MDB_cursor *cur;
+ dbr = mdb_cursor_open(txn, dbi_spent, &cur);
+ CHECK_AND_ASSERT_THROW_MES(!dbr, "Failed to open LMDB cursor: " + std::string(mdb_strerror(dbr)));
+
+ const uint64_t STAT_WINDOW = 10000;
+ uint64_t outs_total = 0;
+ uint64_t outs_spent = 0;
+ std::unordered_map<uint64_t, uint64_t> outs_per_amount;
+ uint64_t start_idx = 0, n_txes;
+ uint64_t prev_height = 0;
+ for_all_transactions(inputs[0], start_idx, n_txes, [&](bool last_tx, uint64_t height, const cryptonote::transaction_prefix &tx)->bool
+ {
+ if (height != prev_height)
+ {
+ if (height % 100 == 0) std::cout << "\r" << height << ": " << (100.0f * outs_spent / outs_total) << "% ( " << outs_spent << " / " << outs_total << " ) \r" << std::flush;
+ if (height % STAT_WINDOW == 0)
+ {
+ uint64_t window_front = (height / STAT_WINDOW - 1) * STAT_WINDOW;
+ uint64_t window_back = window_front + STAT_WINDOW - 1;
+ LOG_PRINT_L0(window_front << "-" << window_back << ": " << (100.0f * outs_spent / outs_total) << "% ( " << outs_spent << " / " << outs_total << " )");
+ outs_total = outs_spent = 0;
+ }
+ }
+ prev_height = height;
+ for (const auto &out: tx.vout)
+ {
+ ++outs_total;
+ CHECK_AND_ASSERT_THROW_MES(out.target.type() == typeid(txout_to_key), "Out target type is not txout_to_key: height=" + std::to_string(height));
+ uint64_t out_global_index = outs_per_amount[out.amount]++;
+ if (is_output_spent(cur, output_data(out.amount, out_global_index)))
+ ++outs_spent;
+ }
+ if (last_tx)
+ {
+ uint64_t window_front = (height / STAT_WINDOW) * STAT_WINDOW;
+ uint64_t window_back = height;
+ LOG_PRINT_L0(window_front << "-" << window_back << ": " << (100.0f * outs_spent / outs_total) << "% ( " << outs_spent << " / " << outs_total << " )");
+ }
+ if (stop_requested)
+ {
+ MINFO("Stopping scan...");
+ return false;
+ }
+ return true;
+ });
+ mdb_cursor_close(cur);
+ dbr = mdb_txn_commit(txn);
+ CHECK_AND_ASSERT_THROW_MES(!dbr, "Failed to commit txn creating/opening database: " + std::string(mdb_strerror(dbr)));
+ goto skip_secondary_passes;
+ }
+
if (!extra_spent_outputs.empty())
{
MINFO("Adding " << extra_spent_outputs.size() << " extra spent outputs");
@@ -1432,8 +1607,6 @@ int main(int argc, char* argv[])
break;
}
- std::vector<output_data> work_spent;
-
if (stop_requested)
goto skip_secondary_passes;
diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c
index 1fa819b57..647471513 100644
--- a/src/crypto/slow-hash.c
+++ b/src/crypto/slow-hash.c
@@ -136,8 +136,8 @@ static inline int use_v4_jit(void)
{ \
U64(b)[2] = state.hs.w[8] ^ state.hs.w[10]; \
U64(b)[3] = state.hs.w[9] ^ state.hs.w[11]; \
- division_result = state.hs.w[12]; \
- sqrt_result = state.hs.w[13]; \
+ division_result = SWAP64LE(state.hs.w[12]); \
+ sqrt_result = SWAP64LE(state.hs.w[13]); \
} while (0)
#define VARIANT2_PORTABLE_INIT() \
@@ -210,7 +210,7 @@ static inline int use_v4_jit(void)
uint64_t b0[2]; \
memcpy_swap64le(b0, b, 2); \
chunk2[0] = SWAP64LE(chunk1_old[0] + b0[0]); \
- chunk2[1] = SWAP64LE(SWAP64LE(chunk1_old[1]) + b0[1]); \
+ chunk2[1] = SWAP64LE(chunk1_old[1] + b0[1]); \
if (variant >= 4) \
{ \
uint64_t out_copy[2]; \
diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h
index 02ed89e5a..771deb04c 100644
--- a/src/cryptonote_basic/difficulty.h
+++ b/src/cryptonote_basic/difficulty.h
@@ -34,7 +34,6 @@
#include <vector>
#include <string>
#include <boost/multiprecision/cpp_int.hpp>
-
#include "crypto/hash.h"
namespace cryptonote
diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h
index 173b454f6..4147b48ee 100644
--- a/src/cryptonote_config.h
+++ b/src/cryptonote_config.h
@@ -160,6 +160,9 @@
#define HF_VERSION_SMALLER_BP 10
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT 10
#define HF_VERSION_MIN_2_OUTPUTS 12
+#define HF_VERSION_MIN_V2_COINBASE_TX 12
+#define HF_VERSION_SAME_MIXIN 12
+#define HF_VERSION_REJECT_SIGS_IN_COINBASE 12
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 8ed0e526a..798a73c4f 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -616,7 +616,7 @@ bool Blockchain::deinit()
// It starts a batch and calls private method pop_block_from_blockchain().
void Blockchain::pop_blocks(uint64_t nblocks)
{
- uint64_t i;
+ uint64_t i = 0;
CRITICAL_REGION_LOCAL(m_tx_pool);
CRITICAL_REGION_LOCAL1(m_blockchain_lock);
@@ -627,9 +627,10 @@ void Blockchain::pop_blocks(uint64_t nblocks)
const uint64_t blockchain_height = m_db->height();
if (blockchain_height > 0)
nblocks = std::min(nblocks, blockchain_height - 1);
- for (i=0; i < nblocks; ++i)
+ while (i < nblocks)
{
pop_block_from_blockchain();
+ ++i;
}
}
catch (const std::exception& e)
@@ -1201,11 +1202,19 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
// one input, of type txin_gen, with height set to the block's height
// correct miner tx unlock time
// a non-overflowing tx amount (dubious necessity on this check)
-bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height)
+bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height, uint8_t hf_version)
{
LOG_PRINT_L3("Blockchain::" << __func__);
CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, false, "coinbase transaction in the block has no inputs");
CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "coinbase transaction in the block has the wrong type");
+ CHECK_AND_ASSERT_MES(b.miner_tx.version > 1 || hf_version < HF_VERSION_MIN_V2_COINBASE_TX, false, "Invalid coinbase transaction version");
+
+ // for v2 txes (ringct), we only accept empty rct signatures for miner transactions,
+ if (hf_version >= HF_VERSION_REJECT_SIGS_IN_COINBASE && b.miner_tx.version >= 2)
+ {
+ CHECK_AND_ASSERT_MES(b.miner_tx.rct_signatures.type == rct::RCTTypeNull, false, "RingCT signatures not allowed in coinbase transactions");
+ }
+
if(boost::get<txin_gen>(b.miner_tx.vin[0]).height != height)
{
MWARNING("The miner transaction in block has invalid height: " << boost::get<txin_gen>(b.miner_tx.vin[0]).height << ", expected: " << height);
@@ -1712,6 +1721,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
}
// this is a cheap test
+ const uint8_t hf_version = m_hardfork->get_ideal_version(block_height);
if (!m_hardfork->check_for_height(b, block_height))
{
LOG_PRINT_L1("Block with id: " << id << std::endl << "has old version for height " << block_height);
@@ -1770,7 +1780,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
return false;
}
- if(!prevalidate_miner_transaction(b, bei.height))
+ if(!prevalidate_miner_transaction(b, bei.height, hf_version))
{
MERROR_VER("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative) has incorrect miner transaction.");
bvc.m_verifivation_failed = true;
@@ -2858,7 +2868,8 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
if (hf_version >= 2)
{
size_t n_unmixable = 0, n_mixable = 0;
- size_t mixin = std::numeric_limits<size_t>::max();
+ size_t min_actual_mixin = std::numeric_limits<size_t>::max();
+ size_t max_actual_mixin = 0;
const size_t min_mixin = hf_version >= HF_VERSION_MIN_MIXIN_10 ? 10 : hf_version >= HF_VERSION_MIN_MIXIN_6 ? 6 : hf_version >= HF_VERSION_MIN_MIXIN_4 ? 4 : 2;
for (const auto& txin : tx.vin)
{
@@ -2883,29 +2894,43 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
else
++n_mixable;
}
- if (in_to_key.key_offsets.size() - 1 < mixin)
- mixin = in_to_key.key_offsets.size() - 1;
+ size_t ring_mixin = in_to_key.key_offsets.size() - 1;
+ if (ring_mixin < min_actual_mixin)
+ min_actual_mixin = ring_mixin;
+ if (ring_mixin > max_actual_mixin)
+ max_actual_mixin = ring_mixin;
}
}
+ MDEBUG("Mixin: " << min_actual_mixin << "-" << max_actual_mixin);
- if (((hf_version == HF_VERSION_MIN_MIXIN_10 || hf_version == HF_VERSION_MIN_MIXIN_10+1) && mixin != 10) || (hf_version >= HF_VERSION_MIN_MIXIN_10+2 && mixin > 10))
+ if (hf_version >= HF_VERSION_SAME_MIXIN)
{
- MERROR_VER("Tx " << get_transaction_hash(tx) << " has invalid ring size (" << (mixin + 1) << "), it should be 11");
+ if (min_actual_mixin != max_actual_mixin)
+ {
+ MERROR_VER("Tx " << get_transaction_hash(tx) << " has varying ring size (" << (min_actual_mixin + 1) << "-" << (max_actual_mixin + 1) << "), it should be constant");
+ tvc.m_low_mixin = true;
+ return false;
+ }
+ }
+
+ if (((hf_version == HF_VERSION_MIN_MIXIN_10 || hf_version == HF_VERSION_MIN_MIXIN_10+1) && min_actual_mixin != 10) || (hf_version >= HF_VERSION_MIN_MIXIN_10+2 && min_actual_mixin > 10))
+ {
+ MERROR_VER("Tx " << get_transaction_hash(tx) << " has invalid ring size (" << (min_actual_mixin + 1) << "), it should be 11");
tvc.m_low_mixin = true;
return false;
}
- if (mixin < min_mixin)
+ if (min_actual_mixin < min_mixin)
{
if (n_unmixable == 0)
{
- MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low ring size (" << (mixin + 1) << "), and no unmixable inputs");
+ MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low ring size (" << (min_actual_mixin + 1) << "), and no unmixable inputs");
tvc.m_low_mixin = true;
return false;
}
if (n_mixable > 1)
{
- MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low ring size (" << (mixin + 1) << "), and more than one mixable input with unmixable inputs");
+ MERROR_VER("Tx " << get_transaction_hash(tx) << " has too low ring size (" << (min_actual_mixin + 1) << "), and more than one mixable input with unmixable inputs");
tvc.m_low_mixin = true;
return false;
}
@@ -3588,9 +3613,10 @@ leave:
}
// this is a cheap test
+ const uint8_t hf_version = get_current_hard_fork_version();
if (!m_hardfork->check(bl))
{
- MERROR_VER("Block with id: " << id << std::endl << "has old version: " << (unsigned)bl.major_version << std::endl << "current: " << (unsigned)m_hardfork->get_current_version());
+ MERROR_VER("Block with id: " << id << std::endl << "has old version: " << (unsigned)bl.major_version << std::endl << "current: " << (unsigned)hf_version);
bvc.m_verifivation_failed = true;
goto leave;
}
@@ -3695,7 +3721,7 @@ leave:
TIME_MEASURE_START(t3);
// sanity check basic miner tx properties;
- if(!prevalidate_miner_transaction(bl, blockchain_height))
+ if(!prevalidate_miner_transaction(bl, blockchain_height, hf_version))
{
MERROR_VER("Block with id: " << id << " failed to pass prevalidation");
bvc.m_verifivation_failed = true;
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index f58059a6d..f32645949 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -1245,10 +1245,11 @@ namespace cryptonote
*
* @param b the block containing the miner transaction
* @param height the height at which the block will be added
+ * @param hf_version the consensus rules to apply
*
* @return false if anything is found wrong with the miner transaction, otherwise true
*/
- bool prevalidate_miner_transaction(const block& b, uint64_t height);
+ bool prevalidate_miner_transaction(const block& b, uint64_t height, uint8_t hf_version);
/**
* @brief validates a miner (coinbase) transaction
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index a3a92ab60..0147bde23 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1630,18 +1630,18 @@ namespace cryptonote
return true;
HardFork::State state = m_blockchain_storage.get_hard_fork_state();
- const el::Level level = el::Level::Warning;
+ el::Level level;
switch (state) {
case HardFork::LikelyForked:
+ level = el::Level::Warning;
MCLOG_RED(level, "global", "**********************************************************************");
MCLOG_RED(level, "global", "Last scheduled hard fork is too far in the past.");
MCLOG_RED(level, "global", "We are most likely forked from the network. Daemon update needed now.");
MCLOG_RED(level, "global", "**********************************************************************");
break;
case HardFork::UpdateNeeded:
- MCLOG_RED(level, "global", "**********************************************************************");
- MCLOG_RED(level, "global", "Last scheduled hard fork time shows a daemon update is needed soon.");
- MCLOG_RED(level, "global", "**********************************************************************");
+ level = el::Level::Info;
+ MCLOG(level, "global", "Last scheduled hard fork time suggests a daemon update will be released within the next couple months.");
break;
default:
break;
diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp
index 924447701..d47823735 100644
--- a/src/daemon/command_parser_executor.cpp
+++ b/src/daemon/command_parser_executor.cpp
@@ -51,12 +51,14 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>&
{
if (args.size() > 3)
{
- std::cout << "use: print_pl [white] [gray] [<limit>]" << std::endl;
+ std::cout << "use: print_pl [white] [gray] [<limit>] [pruned] [publicrpc]" << std::endl;
return true;
}
bool white = false;
bool gray = false;
+ bool pruned = false;
+ bool publicrpc = false;
size_t limit = 0;
for (size_t i = 0; i < args.size(); ++i)
{
@@ -68,6 +70,14 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>&
{
gray = true;
}
+ else if (args[i] == "pruned")
+ {
+ pruned = true;
+ }
+ else if (args[i] == "publicrpc")
+ {
+ publicrpc = true;
+ }
else if (!epee::string_tools::get_xtype_from_string(limit, args[i]))
{
std::cout << "unexpected argument: " << args[i] << std::endl;
@@ -76,7 +86,7 @@ bool t_command_parser_executor::print_peer_list(const std::vector<std::string>&
}
const bool print_both = !white && !gray;
- return m_executor.print_peer_list(white | print_both, gray | print_both, limit);
+ return m_executor.print_peer_list(white | print_both, gray | print_both, limit, pruned, publicrpc);
}
bool t_command_parser_executor::print_peer_list_stats(const std::vector<std::string>& args)
@@ -813,4 +823,18 @@ bool t_command_parser_executor::check_blockchain_pruning(const std::vector<std::
return m_executor.check_blockchain_pruning();
}
+bool t_command_parser_executor::set_bootstrap_daemon(const std::vector<std::string>& args)
+{
+ const size_t args_count = args.size();
+ if (args_count < 1 || args_count > 3)
+ {
+ return false;
+ }
+
+ return m_executor.set_bootstrap_daemon(
+ args[0] != "none" ? args[0] : std::string(),
+ args_count > 1 ? args[1] : std::string(),
+ args_count > 2 ? args[2] : std::string());
+}
+
} // namespace daemonize
diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h
index d39bc1c9b..25587dea8 100644
--- a/src/daemon/command_parser_executor.h
+++ b/src/daemon/command_parser_executor.h
@@ -150,6 +150,8 @@ public:
bool check_blockchain_pruning(const std::vector<std::string>& args);
bool print_net_stats(const std::vector<std::string>& args);
+
+ bool set_bootstrap_daemon(const std::vector<std::string>& args);
};
} // namespace daemonize
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index aecdda52c..757e072a4 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -310,6 +310,13 @@ t_command_server::t_command_server(
, std::bind(&t_command_parser_executor::check_blockchain_pruning, &m_parser, p::_1)
, "Check the blockchain pruning."
);
+ m_command_lookup.set_handler(
+ "set_bootstrap_daemon"
+ , std::bind(&t_command_parser_executor::set_bootstrap_daemon, &m_parser, p::_1)
+ , "set_bootstrap_daemon (auto | none | host[:port] [username] [password])"
+ , "URL of a 'bootstrap' remote daemon that the connected wallets can use while this daemon is still not fully synced.\n"
+ "Use 'auto' to enable automatic public nodes discovering and bootstrap daemon switching"
+ );
}
bool t_command_server::process_command_str(const std::string& cmd)
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 4d3debed6..014865730 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -60,13 +60,18 @@ namespace {
}
}
- void print_peer(std::string const & prefix, cryptonote::peer const & peer)
+ void print_peer(std::string const & prefix, cryptonote::peer const & peer, bool pruned_only, bool publicrpc_only)
{
+ if (pruned_only && peer.pruning_seed == 0)
+ return;
+ if (publicrpc_only && peer.rpc_port == 0)
+ return;
+
time_t now;
time(&now);
time_t last_seen = static_cast<time_t>(peer.last_seen);
- std::string elapsed = epee::misc_utils::get_time_interval_string(now - last_seen);
+ std::string elapsed = peer.last_seen == 0 ? "never" : epee::misc_utils::get_time_interval_string(now - last_seen);
std::string id_str = epee::string_tools::pad_string(epee::string_tools::to_string_hex(peer.id), 16, '0', true);
std::string port_str;
epee::string_tools::xtype_to_string(peer.port, port_str);
@@ -169,7 +174,7 @@ t_rpc_command_executor::~t_rpc_command_executor()
}
}
-bool t_rpc_command_executor::print_peer_list(bool white, bool gray, size_t limit) {
+bool t_rpc_command_executor::print_peer_list(bool white, bool gray, size_t limit, bool pruned_only, bool publicrpc_only) {
cryptonote::COMMAND_RPC_GET_PEER_LIST::request req;
cryptonote::COMMAND_RPC_GET_PEER_LIST::response res;
@@ -196,7 +201,7 @@ bool t_rpc_command_executor::print_peer_list(bool white, bool gray, size_t limit
const auto end = limit ? peer + std::min(limit, res.white_list.size()) : res.white_list.cend();
for (; peer != end; ++peer)
{
- print_peer("white", *peer);
+ print_peer("white", *peer, pruned_only, publicrpc_only);
}
}
@@ -206,7 +211,7 @@ bool t_rpc_command_executor::print_peer_list(bool white, bool gray, size_t limit
const auto end = limit ? peer + std::min(limit, res.gray_list.size()) : res.gray_list.cend();
for (; peer != end; ++peer)
{
- print_peer("gray", *peer);
+ print_peer("gray", *peer, pruned_only, publicrpc_only);
}
}
@@ -573,9 +578,9 @@ bool t_rpc_command_executor::mining_status() {
tools::msg_writer() << "Mining at " << get_mining_speed(mres.speed) << " with " << mres.threads_count << " threads";
}
+ tools::msg_writer() << "PoW algorithm: " << mres.pow_algorithm;
if (mres.active || mres.is_background_mining_enabled)
{
- tools::msg_writer() << "PoW algorithm: " << mres.pow_algorithm;
tools::msg_writer() << "Mining address: " << mres.address;
}
@@ -2320,4 +2325,40 @@ bool t_rpc_command_executor::check_blockchain_pruning()
return true;
}
+bool t_rpc_command_executor::set_bootstrap_daemon(
+ const std::string &address,
+ const std::string &username,
+ const std::string &password)
+{
+ cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::request req;
+ cryptonote::COMMAND_RPC_SET_BOOTSTRAP_DAEMON::response res;
+ const std::string fail_message = "Unsuccessful";
+
+ req.address = address;
+ req.username = username;
+ req.password = password;
+
+ if (m_is_rpc)
+ {
+ if (!m_rpc_client->rpc_request(req, res, "/set_bootstrap_daemon", fail_message))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ if (!m_rpc_server->on_set_bootstrap_daemon(req, res) || res.status != CORE_RPC_STATUS_OK)
+ {
+ tools::fail_msg_writer() << make_error(fail_message, res.status);
+ return true;
+ }
+ }
+
+ tools::success_msg_writer()
+ << "Successfully set bootstrap daemon address to "
+ << (!req.address.empty() ? req.address : "none");
+
+ return true;
+}
+
}// namespace daemonize
diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h
index f3ed48319..af7081ef3 100644
--- a/src/daemon/rpc_command_executor.h
+++ b/src/daemon/rpc_command_executor.h
@@ -69,7 +69,7 @@ public:
~t_rpc_command_executor();
- bool print_peer_list(bool white = true, bool gray = true, size_t limit = 0);
+ bool print_peer_list(bool white = true, bool gray = true, size_t limit = 0, bool pruned_only = false, bool publicrpc_only = false);
bool print_peer_list_stats();
@@ -162,6 +162,11 @@ public:
bool check_blockchain_pruning();
bool print_net_stats();
+
+ bool set_bootstrap_daemon(
+ const std::string &address,
+ const std::string &username,
+ const std::string &password);
};
} // namespace daemonize
diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp
index 2d91b881b..15fe560d1 100644
--- a/src/device/device_ledger.cpp
+++ b/src/device/device_ledger.cpp
@@ -418,10 +418,10 @@ namespace hw {
#ifdef DEBUG_HWDEVICE
cryptonote::account_public_address pubkey;
this->get_public_address(pubkey);
- #endif
crypto::secret_key vkey;
crypto::secret_key skey;
this->get_secret_keys(vkey,skey);
+ #endif
return true;
}
diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h
index 231175dd2..255a1fc1f 100644
--- a/src/p2p/net_node.h
+++ b/src/p2p/net_node.h
@@ -355,8 +355,7 @@ namespace nodetool
bool get_local_node_data(basic_node_data& node_data, const network_zone& zone);
//bool get_local_handshake_data(handshake_data& hshd);
- bool merge_peerlist_with_local(const std::vector<peerlist_entry>& bs);
- bool fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
+ bool sanitize_peerlist(std::vector<peerlist_entry>& local_peerlist);
bool connections_maker();
bool peer_sync_idle_maker();
diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl
index 41ca19917..97a18b519 100644
--- a/src/p2p/net_node.inl
+++ b/src/p2p/net_node.inl
@@ -1446,7 +1446,7 @@ namespace nodetool
if (skipped == 0 || !filtered.empty())
break;
if (skipped)
- MGINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers");
+ MINFO("Skipping " << skipped << " possible peers as they share a class B with existing peers");
}
if (filtered.empty())
{
@@ -1841,21 +1841,32 @@ namespace nodetool
}
//-----------------------------------------------------------------------------------
template<class t_payload_net_handler>
- bool node_server<t_payload_net_handler>::fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
+ bool node_server<t_payload_net_handler>::sanitize_peerlist(std::vector<peerlist_entry>& local_peerlist)
{
- //fix time delta
- time_t now = 0;
- time(&now);
- delta = now - local_time;
-
- for(peerlist_entry& be: local_peerlist)
+ for (size_t i = 0; i < local_peerlist.size(); ++i)
{
- if(be.last_seen > local_time)
+ bool ignore = false;
+ peerlist_entry &be = local_peerlist[i];
+ epee::net_utils::network_address &na = be.adr;
+ if (na.is_loopback() || na.is_local())
{
- MWARNING("FOUND FUTURE peerlist for entry " << be.adr.str() << " last_seen: " << be.last_seen << ", local_time(on remote node):" << local_time);
- return false;
+ ignore = true;
+ }
+ else if (be.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
+ {
+ const epee::net_utils::ipv4_network_address &ipv4 = na.as<const epee::net_utils::ipv4_network_address>();
+ if (ipv4.ip() == 0)
+ ignore = true;
+ }
+ if (ignore)
+ {
+ MDEBUG("Ignoring " << be.adr.str());
+ std::swap(local_peerlist[i], local_peerlist[local_peerlist.size() - 1]);
+ local_peerlist.resize(local_peerlist.size() - 1);
+ --i;
+ continue;
}
- be.last_seen += delta;
+
#ifdef CRYPTONOTE_PRUNING_DEBUG_SPOOF_SEED
be.pruning_seed = tools::make_pruning_seed(1 + (be.adr.as<epee::net_utils::ipv4_network_address>().ip()) % (1ul << CRYPTONOTE_PRUNING_LOG_STRIPES), CRYPTONOTE_PRUNING_LOG_STRIPES);
#endif
@@ -1866,9 +1877,8 @@ namespace nodetool
template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context)
{
- int64_t delta = 0;
std::vector<peerlist_entry> peerlist_ = peerlist;
- if(!fix_time_delta(peerlist_, local_time, delta))
+ if(!sanitize_peerlist(peerlist_))
return false;
const epee::net_utils::zone zone = context.m_remote_address.get_zone();
@@ -1881,8 +1891,8 @@ namespace nodetool
}
}
- LOG_DEBUG_CC(context, "REMOTE PEERLIST: TIME_DELTA: " << delta << ", remote peerlist size=" << peerlist_.size());
- LOG_DEBUG_CC(context, "REMOTE PEERLIST: " << print_peerlist_to_string(peerlist_));
+ LOG_DEBUG_CC(context, "REMOTE PEERLIST: remote peerlist size=" << peerlist_.size());
+ LOG_DEBUG_CC(context, "REMOTE PEERLIST: " << ENDL << print_peerlist_to_string(peerlist_));
return m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.merge_peerlist(peerlist_);
}
//-----------------------------------------------------------------------------------
@@ -2308,6 +2318,15 @@ namespace nodetool
network_zone& zone = m_network_zones.at(context.m_remote_address.get_zone());
+ // test only the remote end's zone, otherwise an attacker could connect to you on clearnet
+ // and pass in a tor connection's peer id, and deduce the two are the same if you reject it
+ if(arg.node_data.peer_id == zone.m_config.m_peer_id)
+ {
+ LOG_DEBUG_CC(context, "Connection to self detected, dropping connection");
+ drop_connection(context);
+ return 1;
+ }
+
if (zone.m_current_number_of_in_peers >= zone.m_config.m_net_config.max_in_connection_count) // in peers limit
{
LOG_WARNING_CC(context, "COMMAND_HANDSHAKE came, but already have max incoming connections, so dropping this one.");
@@ -2334,7 +2353,7 @@ namespace nodetool
context.m_in_timedsync = false;
context.m_rpc_port = arg.node_data.rpc_port;
- if(arg.node_data.peer_id != zone.m_config.m_peer_id && arg.node_data.my_port && zone.m_can_pingback)
+ if(arg.node_data.my_port && zone.m_can_pingback)
{
peerid_type peer_id_l = arg.node_data.peer_id;
uint32_t port_l = arg.node_data.my_port;
diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h
index 05eb36e65..c2773981c 100644
--- a/src/p2p/net_peerlist_boost_serialization.h
+++ b/src/p2p/net_peerlist_boost_serialization.h
@@ -95,7 +95,9 @@ namespace boost
{
uint32_t ip{na.ip()};
uint16_t port{na.port()};
+ ip = SWAP32LE(ip);
a & ip;
+ ip = SWAP32LE(ip);
a & port;
if (!typename Archive::is_saving())
na = epee::net_utils::ipv4_network_address{ip, port};
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 706776ae0..529cdbf2d 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -103,6 +103,7 @@ namespace cryptonote
)
: m_core(cr)
, m_p2p(p2p)
+ , m_was_bootstrap_ever_used(false)
{}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::set_bootstrap_daemon(const std::string &address, const std::string &username_password)
@@ -1049,7 +1050,8 @@ namespace cryptonote
res.block_reward = lMiner.get_block_reward();
}
const account_public_address& lMiningAdr = lMiner.get_mining_address();
- res.address = get_account_address_as_str(nettype(), false, lMiningAdr);
+ if (lMiner.is_mining() || lMiner.get_is_background_mining_enabled())
+ res.address = get_account_address_as_str(nettype(), false, lMiningAdr);
const uint8_t major_version = m_core.get_blockchain_storage().get_current_hard_fork_version();
const unsigned variant = major_version >= 7 ? major_version - 6 : 0;
switch (variant)
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index 325ac4343..2f7f22293 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -255,56 +255,6 @@ namespace cryptonote
};
typedef epee::misc_utils::struct_init<response_t> response;
};
-
- //-----------------------------------------------
- struct COMMAND_RPC_GET_RANDOM_OUTS
- {
- struct request_t
- {
- std::vector<std::string> amounts;
- uint32_t count;
-
- BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(amounts)
- KV_SERIALIZE(count)
- END_KV_SERIALIZE_MAP()
- };
- typedef epee::misc_utils::struct_init<request_t> request;
-
-
- struct output {
- std::string public_key;
- uint64_t global_index;
- std::string rct; // 64+64+64 characters long (<rct commit> + <encrypted mask> + <rct amount>)
-
- BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(public_key)
- KV_SERIALIZE(global_index)
- KV_SERIALIZE(rct)
- END_KV_SERIALIZE_MAP()
- };
-
- struct amount_out {
- uint64_t amount;
- std::vector<output> outputs;
- BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(amount)
- KV_SERIALIZE(outputs)
- END_KV_SERIALIZE_MAP()
-
- };
-
- struct response_t
- {
- std::vector<amount_out> amount_outs;
- std::string Error;
- BEGIN_KV_SERIALIZE_MAP()
- KV_SERIALIZE(amount_outs)
- KV_SERIALIZE(Error)
- END_KV_SERIALIZE_MAP()
- };
- typedef epee::misc_utils::struct_init<response_t> response;
- };
//-----------------------------------------------
struct COMMAND_RPC_SUBMIT_RAW_TX
{
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index af8d7526d..fe384e529 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -2283,9 +2283,16 @@ bool simple_wallet::set_default_ring_size(const std::vector<std::string> &args/*
}
if (ring_size != 0 && ring_size != DEFAULT_MIX+1)
- message_writer() << tr("WARNING: this is a non default ring size, which may harm your privacy. Default is recommended.");
- else if (ring_size == DEFAULT_MIX)
- message_writer() << tr("WARNING: from v8, ring size will be fixed and this setting will be ignored.");
+ {
+ if (m_wallet->use_fork_rules(8, 0))
+ {
+ message_writer() << tr("WARNING: from v8, ring size will be fixed and this setting will be ignored.");
+ }
+ else
+ {
+ message_writer() << tr("WARNING: this is a non default ring size, which may harm your privacy. Default is recommended.");
+ }
+ }
const auto pwd_container = get_and_verify_password();
if (pwd_container)
@@ -4196,7 +4203,22 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
if (!m_wallet->is_trusted_daemon())
- message_writer() << (boost::format(tr("Warning: using an untrusted daemon at %s, privacy will be lessened")) % m_wallet->get_daemon_address()).str();
+ {
+ message_writer(console_color_red, true) << (boost::format(tr("Warning: using an untrusted daemon at %s")) % m_wallet->get_daemon_address()).str();
+ message_writer(console_color_red, true) << boost::format(tr("Using a third party daemon can be detrimental to your security and privacy"));
+ bool ssl = false;
+ if (m_wallet->check_connection(NULL, &ssl) && !ssl)
+ message_writer(console_color_red, true) << boost::format(tr("Using your own without SSL exposes your RPC traffic to monitoring"));
+ message_writer(console_color_red, true) << boost::format(tr("You are strongly encouraged to connect to the Monero network using your own daemon"));
+ message_writer(console_color_red, true) << boost::format(tr("If you or someone you trust are operating this daemon, you can use --trusted-daemon"));
+
+ COMMAND_RPC_GET_INFO::request req;
+ COMMAND_RPC_GET_INFO::response res;
+ bool r = m_wallet->invoke_http_json("/get_info", req, res);
+ std::string err = interpret_rpc_response(r, res.status);
+ if (r && err.empty() && (res.was_bootstrap_ever_used || !res.bootstrap_daemon_address.empty()))
+ message_writer(console_color_red, true) << boost::format(tr("Moreover, a daemon is also less secure when running in bootstrap mode"));
+ }
if (m_wallet->get_ring_database().empty())
fail_msg_writer() << tr("Failed to initialize ring database: privacy enhancing features will be inactive");
@@ -4446,7 +4468,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
}
success_msg_writer() << "**********************************************************************";
- return std::move(password);
+ return password;
}
//----------------------------------------------------------------------------------------------------
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
@@ -4495,7 +4517,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
}
- return std::move(password);
+ return password;
}
//----------------------------------------------------------------------------------------------------
@@ -4538,7 +4560,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
return {};
}
- return std::move(password);
+ return password;
}
//----------------------------------------------------------------------------------------------------
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
@@ -4593,7 +4615,7 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
return {};
}
- return std::move(password);
+ return password;
}
//----------------------------------------------------------------------------------------------------
boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
@@ -4696,7 +4718,7 @@ boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::p
tr("Use the \"help\" command to see the list of available commands.\n") <<
tr("Use \"help <command>\" to see a command's documentation.\n") <<
"**********************************************************************";
- return std::move(password);
+ return password;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::close_wallet()
@@ -5320,14 +5342,14 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
uint64_t blocks_to_unlock;
- uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, &blocks_to_unlock);
+ uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, false, &blocks_to_unlock);
std::string unlock_time_message;
if (blocks_to_unlock > 0)
unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
- success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account)) << ", "
+ success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account, false)) << ", "
<< tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra;
- std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account);
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
+ std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account, false);
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account, false);
if (!detailed || balance_per_subaddress.empty())
return true;
success_msg_writer() << tr("Balance per address:");
@@ -5859,14 +5881,11 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
priority = m_wallet->adjust_priority(priority);
- size_t fake_outs_count = 0;
+ size_t fake_outs_count = DEFAULT_MIX;
if(local_args.size() > 0) {
size_t ring_size;
if(!epee::string_tools::get_xtype_from_string(ring_size, local_args[0]))
{
- fake_outs_count = m_wallet->default_mixin();
- if (fake_outs_count == 0)
- fake_outs_count = DEFAULT_MIX;
}
else if (ring_size == 0)
{
@@ -6480,14 +6499,11 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
priority = m_wallet->adjust_priority(priority);
- size_t fake_outs_count = 0;
+ size_t fake_outs_count = DEFAULT_MIX;
if(local_args.size() > 0) {
size_t ring_size;
if(!epee::string_tools::get_xtype_from_string(ring_size, local_args[0]))
{
- fake_outs_count = m_wallet->default_mixin();
- if (fake_outs_count == 0)
- fake_outs_count = DEFAULT_MIX;
}
else if (ring_size == 0)
{
@@ -6779,14 +6795,11 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
priority = m_wallet->adjust_priority(priority);
- size_t fake_outs_count = 0;
+ size_t fake_outs_count = DEFAULT_MIX;
if(local_args.size() > 0) {
size_t ring_size;
if(!epee::string_tools::get_xtype_from_string(ring_size, local_args[0]))
{
- fake_outs_count = m_wallet->default_mixin();
- if (fake_outs_count == 0)
- fake_outs_count = DEFAULT_MIX;
}
else if (ring_size == 0)
{
@@ -8728,7 +8741,7 @@ void simple_wallet::print_accounts()
print_accounts("");
if (num_untagged_accounts < m_wallet->get_num_subaddress_accounts())
- success_msg_writer() << tr("\nGrand total:\n Balance: ") << print_money(m_wallet->balance_all()) << tr(", unlocked balance: ") << print_money(m_wallet->unlocked_balance_all());
+ success_msg_writer() << tr("\nGrand total:\n Balance: ") << print_money(m_wallet->balance_all(false)) << tr(", unlocked balance: ") << print_money(m_wallet->unlocked_balance_all(false));
}
//----------------------------------------------------------------------------------------------------
void simple_wallet::print_accounts(const std::string& tag)
@@ -8758,11 +8771,11 @@ void simple_wallet::print_accounts(const std::string& tag)
% (m_current_subaddress_account == account_index ? '*' : ' ')
% account_index
% m_wallet->get_subaddress_as_str({account_index, 0}).substr(0, 6)
- % print_money(m_wallet->balance(account_index))
- % print_money(m_wallet->unlocked_balance(account_index))
+ % print_money(m_wallet->balance(account_index, false))
+ % print_money(m_wallet->unlocked_balance(account_index, false))
% m_wallet->get_subaddress_label({account_index, 0});
- total_balance += m_wallet->balance(account_index);
- total_unlocked_balance += m_wallet->unlocked_balance(account_index);
+ total_balance += m_wallet->balance(account_index, false);
+ total_unlocked_balance += m_wallet->unlocked_balance(account_index, false);
}
success_msg_writer() << tr("----------------------------------------------------------------------------------");
success_msg_writer() << boost::format(tr("%15s %21s %21s")) % "Total" % print_money(total_balance) % print_money(total_unlocked_balance);
diff --git a/src/wallet/api/subaddress_account.cpp b/src/wallet/api/subaddress_account.cpp
index 9bc9d1d91..eaaddc11f 100644
--- a/src/wallet/api/subaddress_account.cpp
+++ b/src/wallet/api/subaddress_account.cpp
@@ -64,8 +64,8 @@ void SubaddressAccountImpl::refresh()
i,
m_wallet->m_wallet->get_subaddress_as_str({i,0}),
m_wallet->m_wallet->get_subaddress_label({i,0}),
- cryptonote::print_money(m_wallet->m_wallet->balance(i)),
- cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i))
+ cryptonote::print_money(m_wallet->m_wallet->balance(i, false)),
+ cryptonote::print_money(m_wallet->m_wallet->unlocked_balance(i, false))
));
}
}
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index e632b8d23..7120485d5 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -993,12 +993,12 @@ void WalletImpl::setSubaddressLookahead(uint32_t major, uint32_t minor)
uint64_t WalletImpl::balance(uint32_t accountIndex) const
{
- return m_wallet->balance(accountIndex);
+ return m_wallet->balance(accountIndex, false);
}
uint64_t WalletImpl::unlockedBalance(uint32_t accountIndex) const
{
- return m_wallet->unlocked_balance(accountIndex);
+ return m_wallet->unlocked_balance(accountIndex, false);
}
uint64_t WalletImpl::blockChainHeight() const
diff --git a/src/wallet/ringdb.cpp b/src/wallet/ringdb.cpp
index 8da95de7b..b7efdd75c 100644
--- a/src/wallet/ringdb.cpp
+++ b/src/wallet/ringdb.cpp
@@ -424,7 +424,7 @@ bool ringdb::blackball_worker(const std::vector<std::pair<uint64_t, uint64_t>> &
{
case BLACKBALL_BLACKBALL:
MDEBUG("Marking output " << output.first << "/" << output.second << " as spent");
- dbr = mdb_cursor_put(cursor, &key, &data, MDB_APPENDDUP);
+ dbr = mdb_cursor_put(cursor, &key, &data, MDB_NODUPDATA);
if (dbr == MDB_KEYEXIST)
dbr = 0;
break;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index b99fc12e2..86169604a 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1543,6 +1543,7 @@ bool wallet2::is_deprecated() const
//----------------------------------------------------------------------------------------------------
void wallet2::set_spent(size_t idx, uint64_t height)
{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid index");
transfer_details &td = m_transfers[idx];
LOG_PRINT_L2("Setting SPENT at " << height << ": ki " << td.m_key_image << ", amount " << print_money(td.m_amount));
td.m_spent = true;
@@ -1551,12 +1552,32 @@ void wallet2::set_spent(size_t idx, uint64_t height)
//----------------------------------------------------------------------------------------------------
void wallet2::set_unspent(size_t idx)
{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid index");
transfer_details &td = m_transfers[idx];
LOG_PRINT_L2("Setting UNSPENT: ki " << td.m_key_image << ", amount " << print_money(td.m_amount));
td.m_spent = false;
td.m_spent_height = 0;
}
//----------------------------------------------------------------------------------------------------
+bool wallet2::is_spent(const transfer_details &td, bool strict) const
+{
+ if (strict)
+ {
+ return td.m_spent && td.m_spent_height > 0;
+ }
+ else
+ {
+ return td.m_spent;
+ }
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::is_spent(size_t idx, bool strict) const
+{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid index");
+ const transfer_details &td = m_transfers[idx];
+ return is_spent(td, strict);
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::freeze(size_t idx)
{
CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
@@ -3294,7 +3315,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
m_first_refresh_done = true;
- LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", balance (all accounts): " << print_money(balance_all()) << ", unlocked: " << print_money(unlocked_balance_all()));
+ LOG_PRINT_L1("Refresh done, blocks received: " << blocks_fetched << ", balance (all accounts): " << print_money(balance_all(false)) << ", unlocked: " << print_money(unlocked_balance_all(false)));
}
//----------------------------------------------------------------------------------------------------
bool wallet2::refresh(bool trusted_daemon, uint64_t & blocks_fetched, bool& received_money, bool& ok)
@@ -5594,24 +5615,24 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::balance(uint32_t index_major) const
+uint64_t wallet2::balance(uint32_t index_major, bool strict) const
{
uint64_t amount = 0;
if(m_light_wallet)
return m_light_wallet_unlocked_balance;
- for (const auto& i : balance_per_subaddress(index_major))
+ for (const auto& i : balance_per_subaddress(index_major, strict))
amount += i.second;
return amount;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::unlocked_balance(uint32_t index_major, uint64_t *blocks_to_unlock) const
+uint64_t wallet2::unlocked_balance(uint32_t index_major, bool strict, uint64_t *blocks_to_unlock) const
{
uint64_t amount = 0;
if (blocks_to_unlock)
*blocks_to_unlock = 0;
if(m_light_wallet)
return m_light_wallet_balance;
- for (const auto& i : unlocked_balance_per_subaddress(index_major))
+ for (const auto& i : unlocked_balance_per_subaddress(index_major, strict))
{
amount += i.second.first;
if (blocks_to_unlock && i.second.second > *blocks_to_unlock)
@@ -5620,12 +5641,12 @@ uint64_t wallet2::unlocked_balance(uint32_t index_major, uint64_t *blocks_to_unl
return amount;
}
//----------------------------------------------------------------------------------------------------
-std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_major) const
+std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_major, bool strict) const
{
std::map<uint32_t, uint64_t> amount_per_subaddr;
for (const auto& td: m_transfers)
{
- if (td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
+ if (td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
{
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
@@ -5634,8 +5655,10 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
found->second += td.amount();
}
}
- for (const auto& utx: m_unconfirmed_txs)
+ if (!strict)
{
+ for (const auto& utx: m_unconfirmed_txs)
+ {
if (utx.second.m_subaddr_account == index_major && utx.second.m_state != wallet2::unconfirmed_transfer_details::failed)
{
// all changes go to 0-th subaddress (in the current subaddress account)
@@ -5645,17 +5668,18 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
else
found->second += utx.second.m_change;
}
+ }
}
return amount_per_subaddr;
}
//----------------------------------------------------------------------------------------------------
-std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major) const
+std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_subaddress(uint32_t index_major, bool strict) const
{
std::map<uint32_t, std::pair<uint64_t, uint64_t>> amount_per_subaddr;
const uint64_t blockchain_height = get_blockchain_current_height();
for(const transfer_details& td: m_transfers)
{
- if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
+ if(td.m_subaddr_index.major == index_major && !is_spent(td, strict) && !td.m_frozen)
{
uint64_t amount = 0, blocks_to_unlock = 0;
if (is_transfer_unlocked(td))
@@ -5684,15 +5708,15 @@ std::map<uint32_t, std::pair<uint64_t, uint64_t>> wallet2::unlocked_balance_per_
return amount_per_subaddr;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::balance_all() const
+uint64_t wallet2::balance_all(bool strict) const
{
uint64_t r = 0;
for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
- r += balance(index_major);
+ r += balance(index_major, strict);
return r;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::unlocked_balance_all(uint64_t *blocks_to_unlock) const
+uint64_t wallet2::unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock) const
{
uint64_t r = 0;
if (blocks_to_unlock)
@@ -5700,7 +5724,7 @@ uint64_t wallet2::unlocked_balance_all(uint64_t *blocks_to_unlock) const
for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major)
{
uint64_t local_blocks_to_unlock;
- r += unlocked_balance(index_major, blocks_to_unlock ? &local_blocks_to_unlock : NULL);
+ r += unlocked_balance(index_major, strict, blocks_to_unlock ? &local_blocks_to_unlock : NULL);
if (blocks_to_unlock)
*blocks_to_unlock = std::max(*blocks_to_unlock, local_blocks_to_unlock);
}
@@ -6177,8 +6201,8 @@ void wallet2::commit_tx(pending_tx& ptx)
//fee includes dust if dust policy specified it.
LOG_PRINT_L1("Transaction successfully sent. <" << txid << ">" << ENDL
<< "Commission: " << print_money(ptx.fee) << " (dust sent to dust addr: " << print_money((ptx.dust_added_to_fee ? 0 : ptx.dust)) << ")" << ENDL
- << "Balance: " << print_money(balance(ptx.construction_data.subaddr_account)) << ENDL
- << "Unlocked: " << print_money(unlocked_balance(ptx.construction_data.subaddr_account)) << ENDL
+ << "Balance: " << print_money(balance(ptx.construction_data.subaddr_account, false)) << ENDL
+ << "Unlocked: " << print_money(unlocked_balance(ptx.construction_data.subaddr_account, false)) << ENDL
<< "Please, wait for confirmation for your balance to be unlocked.");
}
@@ -6346,7 +6370,7 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
// normally, the tx keys are saved in commit_tx, when the tx is actually sent to the daemon.
// we can't do that here since the tx will be sent from the compromised wallet, which we don't want
// to see that info, so we save it here
- if (store_tx_info() && ptx.tx_key != crypto::null_skey)
+ if (store_tx_info() && tx_key != crypto::null_skey)
{
const crypto::hash txid = get_transaction_hash(ptx.tx);
m_tx_keys.insert(std::make_pair(txid, tx_key));
@@ -7258,9 +7282,7 @@ bool wallet2::unset_ring(const crypto::hash &txid)
bool ok = invoke_http_json("/gettransactions", req, res, rpc_timeout);
m_daemon_rpc_mutex.unlock();
THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to get transaction from daemon");
- if (res.txs.empty())
- return false;
- THROW_WALLET_EXCEPTION_IF(res.txs.size(), error::wallet_internal_error, "Failed to get transaction from daemon");
+ THROW_WALLET_EXCEPTION_IF(res.txs.size() != 1, error::wallet_internal_error, "Failed to get transaction from daemon");
cryptonote::transaction tx;
crypto::hash tx_hash;
@@ -7435,8 +7457,8 @@ void wallet2::light_wallet_get_outs(std::vector<std::vector<tools::wallet2::get_
MDEBUG("LIGHTWALLET - Getting random outs");
- cryptonote::COMMAND_RPC_GET_RANDOM_OUTS::request oreq;
- cryptonote::COMMAND_RPC_GET_RANDOM_OUTS::response ores;
+ tools::COMMAND_RPC_GET_RANDOM_OUTS::request oreq;
+ tools::COMMAND_RPC_GET_RANDOM_OUTS::response ores;
size_t light_wallet_requested_outputs_count = (size_t)((fake_outputs_count + 1) * 1.5 + 1);
@@ -8561,7 +8583,7 @@ 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 (!td.m_spent && !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 (!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)
{
LOG_PRINT_L2("We can use " << i << " alone: " << print_money(td.amount()));
picks.push_back(i);
@@ -8576,13 +8598,13 @@ 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 (!td.m_spent && !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 (!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)
{
LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount()));
for (size_t j = i + 1; j < m_transfers.size(); ++j)
{
const transfer_details& td2 = m_transfers[j];
- if (!td2.m_spent && !td2.m_frozen && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
+ if (!is_spent(td2, false) && !td2.m_frozen && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
{
// update our picks if those outputs are less related than any we
// already found. If the same, don't update, and oldest suitable outputs
@@ -9237,8 +9259,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// throw if attempting a transaction with no money
THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination);
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account);
- std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account);
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account, false);
+ std::map<uint32_t, uint64_t> balance_per_subaddr = balance_per_subaddress(subaddr_account, false);
if (subaddr_indices.empty()) // "index=<N1>[,<N2>,...]" wasn't specified -> use all the indices with non-zero unlocked balance
{
@@ -9284,7 +9306,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
continue;
}
- if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
+ if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
const uint32_t index_minor = td.m_subaddr_index.minor;
auto find_predicate = [&index_minor](const std::pair<uint32_t, std::vector<size_t>>& x) { return x.first == index_minor; };
@@ -9411,7 +9433,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
// if we need to spend money and don't have any left, we fail
if (unused_dust_indices->empty() && unused_transfers_indices->empty()) {
LOG_PRINT_L2("No more outputs to choose from");
- THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account), needed_money, accumulated_fee + needed_fee);
+ THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account, false), needed_money, accumulated_fee + needed_fee);
}
// get a random unspent output and use it to pay part (or all) of the current destination (and maybe next one, etc)
@@ -9629,7 +9651,7 @@ skip_tx:
if (adding_fee)
{
LOG_PRINT_L1("We ran out of outputs while trying to gather final fee");
- THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account), needed_money, accumulated_fee + needed_fee);
+ THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account, false), needed_money, accumulated_fee + needed_fee);
}
LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_money(accumulated_fee) <<
@@ -9764,7 +9786,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
std::vector<size_t> unused_dust_indices;
const bool use_rct = use_fork_rules(4, 0);
- THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet");
+ THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account, false) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet");
std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr;
@@ -9773,7 +9795,7 @@ 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 (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
+ if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
{
fund_found = true;
if (below == 0 || td.amount() < below)
@@ -9821,7 +9843,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && !td.m_frozen && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
+ if (td.m_key_image_known && td.m_key_image == ki && !is_spent(td, false) && !td.m_frozen && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
{
if (td.is_rct() || is_valid_decomposed_amount(td.amount()))
unused_transfers_indices.push_back(i);
@@ -10187,7 +10209,7 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
size_t n = 0;
for (transfer_container::const_iterator i = m_transfers.begin(); i != m_transfers.end(); ++i, ++n)
{
- if (i->m_spent)
+ if (is_spent(*i, false))
continue;
if (i->m_frozen)
continue;
@@ -10201,12 +10223,12 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
return outputs;
}
//----------------------------------------------------------------------------------------------------
-std::vector<uint64_t> wallet2::get_unspent_amounts_vector() const
+std::vector<uint64_t> wallet2::get_unspent_amounts_vector(bool strict) const
{
std::set<uint64_t> set;
for (const auto &td: m_transfers)
{
- if (!td.m_spent && !td.m_frozen)
+ if (!is_spent(td, strict) && !td.m_frozen)
set.insert(td.is_rct() ? 0 : td.amount());
}
std::vector<uint64_t> vector;
@@ -10224,7 +10246,7 @@ std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t co
cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t);
m_daemon_rpc_mutex.lock();
if (is_trusted_daemon())
- req_t.amounts = get_unspent_amounts_vector();
+ req_t.amounts = get_unspent_amounts_vector(false);
req_t.min_count = count;
req_t.max_count = 0;
req_t.unlocked = unlocked;
@@ -11122,8 +11144,8 @@ bool wallet2::check_tx_proof(const cryptonote::transaction &tx, const cryptonote
std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t, uint64_t>> &account_minreserve, const std::string &message)
{
THROW_WALLET_EXCEPTION_IF(m_watch_only || m_multisig, error::wallet_internal_error, "Reserve proof can only be generated by a full wallet");
- THROW_WALLET_EXCEPTION_IF(balance_all() == 0, error::wallet_internal_error, "Zero balance");
- THROW_WALLET_EXCEPTION_IF(account_minreserve && balance(account_minreserve->first) < account_minreserve->second, error::wallet_internal_error,
+ THROW_WALLET_EXCEPTION_IF(balance_all(true) == 0, error::wallet_internal_error, "Zero balance");
+ THROW_WALLET_EXCEPTION_IF(account_minreserve && balance(account_minreserve->first, true) < account_minreserve->second, error::wallet_internal_error,
"Not enough balance in this account for the requested minimum reserve amount");
// determine which outputs to include in the proof
@@ -11131,7 +11153,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details &td = m_transfers[i];
- if (!td.m_spent && !td.m_frozen && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
+ if (!is_spent(td, true) && !td.m_frozen && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
selected_transfers.push_back(i);
}
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 5607602e7..95f6f507a 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -804,14 +804,14 @@ private:
bool reconnect_device();
// locked & unlocked balance of given or current subaddress account
- uint64_t balance(uint32_t subaddr_index_major) const;
- uint64_t unlocked_balance(uint32_t subaddr_index_major, uint64_t *blocks_to_unlock = NULL) const;
+ uint64_t balance(uint32_t subaddr_index_major, bool strict) const;
+ uint64_t unlocked_balance(uint32_t subaddr_index_major, bool strict, uint64_t *blocks_to_unlock = NULL) const;
// locked & unlocked balance per subaddress of given or current subaddress account
- std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major) const;
- std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major) const;
+ std::map<uint32_t, uint64_t> balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress(uint32_t subaddr_index_major, bool strict) const;
// all locked & unlocked balances of all subaddress accounts
- uint64_t balance_all() const;
- uint64_t unlocked_balance_all(uint64_t *blocks_to_unlock = NULL) const;
+ uint64_t balance_all(bool strict) const;
+ uint64_t unlocked_balance_all(bool strict, uint64_t *blocks_to_unlock = NULL) const;
template<typename T>
void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count,
std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs,
@@ -1377,12 +1377,14 @@ private:
void check_acc_out_precomp_once(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const;
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
uint64_t get_upper_transaction_weight_limit() const;
- std::vector<uint64_t> get_unspent_amounts_vector() const;
+ std::vector<uint64_t> get_unspent_amounts_vector(bool strict) const;
uint64_t get_dynamic_base_fee_estimate() const;
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices) const;
void set_spent(size_t idx, uint64_t height);
void set_unspent(size_t idx);
+ bool is_spent(const transfer_details &td, bool strict = true) const;
+ bool is_spent(size_t idx, bool strict = true) const;
void get_outs(std::vector<std::vector<get_outs_entry>> &outs, const std::vector<size_t> &selected_transfers, size_t fake_outputs_count);
bool tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const;
bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector<size_t> &unused_transfers_indices, const std::vector<size_t> &unused_dust_indices) const;
diff --git a/src/wallet/wallet_light_rpc.h b/src/wallet/wallet_light_rpc.h
index 1d35cec33..c2a7dc021 100644
--- a/src/wallet/wallet_light_rpc.h
+++ b/src/wallet/wallet_light_rpc.h
@@ -317,4 +317,51 @@ namespace tools
typedef epee::misc_utils::struct_init<response_t> response;
};
//-----------------------------------------------
+ struct COMMAND_RPC_GET_RANDOM_OUTS
+ {
+ struct request_t
+ {
+ std::vector<std::string> amounts;
+ uint32_t count;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(amounts)
+ KV_SERIALIZE(count)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<request_t> request;
+
+ struct output {
+ std::string public_key;
+ uint64_t global_index;
+ std::string rct; // 64+64+64 characters long (<rct commit> + <encrypted mask> + <rct amount>)
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(public_key)
+ KV_SERIALIZE(global_index)
+ KV_SERIALIZE(rct)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct amount_out {
+ uint64_t amount;
+ std::vector<output> outputs;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(amount)
+ KV_SERIALIZE(outputs)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response_t
+ {
+ std::vector<amount_out> amount_outs;
+ std::string Error;
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(amount_outs)
+ KV_SERIALIZE(Error)
+ END_KV_SERIALIZE_MAP()
+ };
+ typedef epee::misc_utils::struct_init<response_t> response;
+ };
+ //-----------------------------------------------
}
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 7c87e7114..765a6c24e 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -151,6 +151,7 @@ namespace tools
if (m_wallet)
{
m_wallet->store();
+ m_wallet->deinit();
delete m_wallet;
m_wallet = NULL;
}
@@ -326,6 +327,7 @@ namespace tools
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
entry.unlock_time = pd.m_unlock_time;
+ entry.locked = !m_wallet->is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height);
entry.fee = pd.m_fee;
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = pd.m_coinbase ? "block" : "in";
@@ -344,6 +346,7 @@ namespace tools
entry.height = pd.m_block_height;
entry.timestamp = pd.m_timestamp;
entry.unlock_time = pd.m_unlock_time;
+ entry.locked = !m_wallet->is_transfer_unlocked(pd.m_unlock_time, pd.m_block_height);
entry.fee = pd.m_amount_in - pd.m_amount_out;
uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known
entry.amount = pd.m_amount_in - change - entry.fee;
@@ -377,6 +380,7 @@ namespace tools
entry.fee = pd.m_amount_in - pd.m_amount_out;
entry.amount = pd.m_amount_in - pd.m_change - entry.fee;
entry.unlock_time = pd.m_tx.unlock_time;
+ entry.locked = true;
entry.note = m_wallet->get_tx_note(txid);
for (const auto &d: pd.m_dests) {
@@ -405,6 +409,7 @@ namespace tools
entry.timestamp = pd.m_timestamp;
entry.amount = pd.m_amount;
entry.unlock_time = pd.m_unlock_time;
+ entry.locked = true;
entry.fee = pd.m_fee;
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.double_spend_seen = ppd.m_double_spend_seen;
@@ -420,8 +425,8 @@ namespace tools
if (!m_wallet) return not_open(er);
try
{
- res.balance = req.all_accounts ? m_wallet->balance_all() : m_wallet->balance(req.account_index);
- res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(&res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, &res.blocks_to_unlock);
+ res.balance = req.all_accounts ? m_wallet->balance_all(req.strict) : m_wallet->balance(req.account_index, req.strict);
+ res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock);
res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images();
std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account;
std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, uint64_t>>> unlocked_balance_per_subaddress_per_account;
@@ -429,14 +434,14 @@ namespace tools
{
for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index)
{
- balance_per_subaddress_per_account[account_index] = m_wallet->balance_per_subaddress(account_index);
- unlocked_balance_per_subaddress_per_account[account_index] = m_wallet->unlocked_balance_per_subaddress(account_index);
+ balance_per_subaddress_per_account[account_index] = m_wallet->balance_per_subaddress(account_index, req.strict);
+ unlocked_balance_per_subaddress_per_account[account_index] = m_wallet->unlocked_balance_per_subaddress(account_index, req.strict);
}
}
else
{
- balance_per_subaddress_per_account[req.account_index] = m_wallet->balance_per_subaddress(req.account_index);
- unlocked_balance_per_subaddress_per_account[req.account_index] = m_wallet->unlocked_balance_per_subaddress(req.account_index);
+ balance_per_subaddress_per_account[req.account_index] = m_wallet->balance_per_subaddress(req.account_index, req.strict);
+ unlocked_balance_per_subaddress_per_account[req.account_index] = m_wallet->unlocked_balance_per_subaddress(req.account_index, req.strict);
}
std::vector<tools::wallet2::transfer_details> transfers;
m_wallet->get_transfers(transfers);
@@ -594,8 +599,8 @@ namespace tools
wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::subaddress_account_info info;
info.account_index = subaddr_index.major;
info.base_address = m_wallet->get_subaddress_as_str(subaddr_index);
- info.balance = m_wallet->balance(subaddr_index.major);
- info.unlocked_balance = m_wallet->unlocked_balance(subaddr_index.major);
+ info.balance = m_wallet->balance(subaddr_index.major, req.strict_balances);
+ info.unlocked_balance = m_wallet->unlocked_balance(subaddr_index.major, req.strict_balances);
info.label = m_wallet->get_subaddress_label(subaddr_index);
info.tag = account_tags.second[subaddr_index.major];
res.subaddress_accounts.push_back(info);
@@ -1698,6 +1703,7 @@ namespace tools
rpc_payment.amount = payment.m_amount;
rpc_payment.block_height = payment.m_block_height;
rpc_payment.unlock_time = payment.m_unlock_time;
+ rpc_payment.locked = !m_wallet->is_transfer_unlocked(payment.m_unlock_time, payment.m_block_height);
rpc_payment.subaddr_index = payment.m_subaddr_index;
rpc_payment.address = m_wallet->get_subaddress_as_str(payment.m_subaddr_index);
res.payments.push_back(rpc_payment);
@@ -1727,6 +1733,7 @@ namespace tools
rpc_payment.unlock_time = payment.second.m_unlock_time;
rpc_payment.subaddr_index = payment.second.m_subaddr_index;
rpc_payment.address = m_wallet->get_subaddress_as_str(payment.second.m_subaddr_index);
+ rpc_payment.locked = !m_wallet->is_transfer_unlocked(payment.second.m_unlock_time, payment.second.m_block_height);
res.payments.push_back(std::move(rpc_payment));
}
@@ -1781,6 +1788,7 @@ namespace tools
rpc_payment.unlock_time = payment.m_unlock_time;
rpc_payment.subaddr_index = payment.m_subaddr_index;
rpc_payment.address = m_wallet->get_subaddress_as_str(payment.m_subaddr_index);
+ rpc_payment.locked = !m_wallet->is_transfer_unlocked(payment.m_unlock_time, payment.m_block_height);
res.payments.push_back(std::move(rpc_payment));
}
}
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 2dfe6db85..d70de68be 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -47,7 +47,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
-#define WALLET_RPC_VERSION_MINOR 14
+#define WALLET_RPC_VERSION_MINOR 15
#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
@@ -64,10 +64,12 @@ namespace wallet_rpc
uint32_t account_index;
std::set<uint32_t> address_indices;
bool all_accounts;
+ bool strict;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index)
KV_SERIALIZE(address_indices)
KV_SERIALIZE_OPT(all_accounts, false);
+ KV_SERIALIZE_OPT(strict, false);
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -230,9 +232,11 @@ namespace wallet_rpc
struct request_t
{
std::string tag; // all accounts if empty, otherwise those accounts with this tag
+ bool strict_balances;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tag)
+ KV_SERIALIZE_OPT(strict_balances, false)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<request_t> request;
@@ -912,6 +916,7 @@ namespace wallet_rpc
uint64_t amount;
uint64_t block_height;
uint64_t unlock_time;
+ bool locked;
cryptonote::subaddress_index subaddr_index;
std::string address;
@@ -921,6 +926,7 @@ namespace wallet_rpc
KV_SERIALIZE(amount)
KV_SERIALIZE(block_height)
KV_SERIALIZE(unlock_time)
+ KV_SERIALIZE(locked)
KV_SERIALIZE(subaddr_index)
KV_SERIALIZE(address)
END_KV_SERIALIZE_MAP()
@@ -1360,6 +1366,7 @@ namespace wallet_rpc
std::list<transfer_destination> destinations;
std::string type;
uint64_t unlock_time;
+ bool locked;
cryptonote::subaddress_index subaddr_index;
std::vector<cryptonote::subaddress_index> subaddr_indices;
std::string address;
@@ -1378,6 +1385,7 @@ namespace wallet_rpc
KV_SERIALIZE(destinations);
KV_SERIALIZE(type);
KV_SERIALIZE(unlock_time)
+ KV_SERIALIZE(locked)
KV_SERIALIZE(subaddr_index);
KV_SERIALIZE(subaddr_indices);
KV_SERIALIZE(address);
diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp
index 566ec1440..55312bc15 100644
--- a/tests/core_tests/block_validation.cpp
+++ b/tests/core_tests/block_validation.cpp
@@ -640,3 +640,18 @@ bool gen_block_invalid_binary_format::check_all_blocks_purged(cryptonote::core&
return true;
}
+
+bool gen_block_late_v1_coinbase_tx::generate(std::vector<test_event_entry>& events) const
+{
+ BLOCK_VALIDATION_INIT_GENERATE();
+
+ block blk_1;
+ generator.construct_block_manually(blk_1, blk_0, miner_account,
+ test_generator::bf_major_ver | test_generator::bf_minor_ver,
+ HF_VERSION_MIN_V2_COINBASE_TX, HF_VERSION_MIN_V2_COINBASE_TX);
+ events.push_back(blk_1);
+
+ DO_CALLBACK(events, "check_block_purged");
+
+ return true;
+}
diff --git a/tests/core_tests/block_validation.h b/tests/core_tests/block_validation.h
index 4a65b029e..2393e1b01 100644
--- a/tests/core_tests/block_validation.h
+++ b/tests/core_tests/block_validation.h
@@ -206,3 +206,15 @@ struct gen_block_invalid_binary_format : public test_chain_unit_base
private:
size_t m_corrupt_blocks_begin_idx;
};
+
+struct gen_block_late_v1_coinbase_tx : public gen_block_verification_base<1>
+{
+ bool generate(std::vector<test_event_entry>& events) const;
+};
+template<>
+struct get_test_options<gen_block_late_v1_coinbase_tx> {
+ const std::pair<uint8_t, uint64_t> hard_forks[3] = {std::make_pair(1, 0), std::make_pair(HF_VERSION_MIN_V2_COINBASE_TX, 1), std::make_pair(0, 0)};
+ const cryptonote::test_options test_options = {
+ hard_forks, 0
+ };
+};
diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp
index cb35cfde2..4ee71466e 100644
--- a/tests/core_tests/chaingen_main.cpp
+++ b/tests/core_tests/chaingen_main.cpp
@@ -133,6 +133,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(gen_block_has_invalid_tx);
GENERATE_AND_PLAY(gen_block_is_too_big);
GENERATE_AND_PLAY(gen_block_invalid_binary_format); // Takes up to 3 hours, if CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW == 500, up to 30 minutes, if CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW == 10
+ GENERATE_AND_PLAY(gen_block_late_v1_coinbase_tx);
// Transaction verification tests
GENERATE_AND_PLAY(gen_tx_big_version);
diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp
index 32b601d7a..2add66b8b 100644
--- a/tests/functional_tests/transactions_flow_test.cpp
+++ b/tests/functional_tests/transactions_flow_test.cpp
@@ -173,7 +173,7 @@ bool transactions_flow_test(std::string& working_folder,
//wait for money, until balance will have enough money
w1.refresh(true, blocks_fetched, received_money, ok);
- while(w1.unlocked_balance(0) < amount_to_transfer)
+ while(w1.unlocked_balance(0, true) < amount_to_transfer)
{
misc_utils::sleep_no_w(1000);
w1.refresh(true, blocks_fetched, received_money, ok);
@@ -186,7 +186,7 @@ bool transactions_flow_test(std::string& working_folder,
{
tools::wallet2::transfer_container incoming_transfers;
w1.get_transfers(incoming_transfers);
- if(incoming_transfers.size() > FIRST_N_TRANSFERS && get_money_in_first_transfers(incoming_transfers, FIRST_N_TRANSFERS) < w1.unlocked_balance(0) )
+ if(incoming_transfers.size() > FIRST_N_TRANSFERS && get_money_in_first_transfers(incoming_transfers, FIRST_N_TRANSFERS) < w1.unlocked_balance(0, true) )
{
//lets go!
size_t count = 0;
@@ -221,7 +221,7 @@ bool transactions_flow_test(std::string& working_folder,
for(i = 0; i != transactions_count; i++)
{
uint64_t amount_to_tx = (amount_to_transfer - transfered_money) > transfer_size ? transfer_size: (amount_to_transfer - transfered_money);
- while(w1.unlocked_balance(0) < amount_to_tx + TEST_FEE)
+ while(w1.unlocked_balance(0, true) < amount_to_tx + TEST_FEE)
{
misc_utils::sleep_no_w(1000);
LOG_PRINT_L0("not enough money, waiting for cashback or mining");
@@ -270,7 +270,7 @@ bool transactions_flow_test(std::string& working_folder,
misc_utils::sleep_no_w(DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN*1000);//wait two blocks before sync on another wallet on another daemon
}
- uint64_t money_2 = w2.balance(0);
+ uint64_t money_2 = w2.balance(0, true);
if(money_2 == transfered_money)
{
MGINFO_GREEN("-----------------------FINISHING TRANSACTIONS FLOW TEST OK-----------------------");
diff --git a/tests/performance_tests/check_hash.h b/tests/performance_tests/check_hash.h
index 53746fec4..294654f37 100644
--- a/tests/performance_tests/check_hash.h
+++ b/tests/performance_tests/check_hash.h
@@ -29,6 +29,7 @@
#pragma once
#include "string_tools.h"
+#include "int-util.h"
#include "cryptonote_basic/difficulty.h"
template<uint64_t hash_target_high, uint64_t hash_target_low, uint64_t difficulty_high, uint64_t difficulty_low>
@@ -44,13 +45,18 @@ public:
difficulty = difficulty_high;
difficulty = (difficulty << 64) | difficulty_low;
boost::multiprecision::uint256_t hash_value = std::numeric_limits<boost::multiprecision::uint256_t>::max() / hash_target;
- ((uint64_t*)&hash)[0] = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ uint64_t val;
+ val = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ ((uint64_t*)&hash)[0] = SWAP64LE(val);
hash_value >>= 64;
- ((uint64_t*)&hash)[1] = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ val = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ ((uint64_t*)&hash)[1] = SWAP64LE(val);
hash_value >>= 64;
- ((uint64_t*)&hash)[2] = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ val = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ ((uint64_t*)&hash)[2] = SWAP64LE(val);
hash_value >>= 64;
- ((uint64_t*)&hash)[3] = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ val = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ ((uint64_t*)&hash)[3] = SWAP64LE(val);
return true;
}
diff --git a/tests/unit_tests/difficulty.cpp b/tests/unit_tests/difficulty.cpp
index a732e6969..e9e3272f0 100644
--- a/tests/unit_tests/difficulty.cpp
+++ b/tests/unit_tests/difficulty.cpp
@@ -27,6 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "gtest/gtest.h"
+#include "int-util.h"
#include "cryptonote_basic/difficulty.h"
static cryptonote::difficulty_type MKDIFF(uint64_t high, uint64_t low)
@@ -42,13 +43,18 @@ static crypto::hash MKHASH(uint64_t high, uint64_t low)
hash_target = (hash_target << 64) | low;
boost::multiprecision::uint256_t hash_value = std::numeric_limits<boost::multiprecision::uint256_t>::max() / hash_target;
crypto::hash h;
- ((uint64_t*)&h)[0] = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ uint64_t val;
+ val = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ ((uint64_t*)&h)[0] = SWAP64LE(val);
hash_value >>= 64;
- ((uint64_t*)&h)[1] = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ val = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ ((uint64_t*)&h)[1] = SWAP64LE(val);
hash_value >>= 64;
- ((uint64_t*)&h)[2] = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ val = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ ((uint64_t*)&h)[2] = SWAP64LE(val);
hash_value >>= 64;
- ((uint64_t*)&h)[3] = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ val = (hash_value & 0xffffffffffffffff).convert_to<uint64_t>();
+ ((uint64_t*)&h)[3] = SWAP64LE(val);
return h;
}
diff --git a/tests/unit_tests/epee_levin_protocol_handler_async.cpp b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
index 7bdb4c43d..b27699a77 100644
--- a/tests/unit_tests/epee_levin_protocol_handler_async.cpp
+++ b/tests/unit_tests/epee_levin_protocol_handler_async.cpp
@@ -241,13 +241,13 @@ namespace
m_in_data.assign(256, 't');
- m_req_head.m_signature = LEVIN_SIGNATURE;
- m_req_head.m_cb = m_in_data.size();
+ m_req_head.m_signature = SWAP64LE(LEVIN_SIGNATURE);
+ m_req_head.m_cb = SWAP64LE(m_in_data.size());
m_req_head.m_have_to_return_data = true;
- m_req_head.m_command = expected_command;
- m_req_head.m_return_code = LEVIN_OK;
- m_req_head.m_flags = LEVIN_PACKET_REQUEST;
- m_req_head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ m_req_head.m_command = SWAP32LE(expected_command);
+ m_req_head.m_return_code = SWAP32LE(LEVIN_OK);
+ m_req_head.m_flags = SWAP32LE(LEVIN_PACKET_REQUEST);
+ m_req_head.m_protocol_version = SWAP32LE(LEVIN_PROTOCOL_VER_1);
m_commands_handler.return_code(expected_return_code);
m_commands_handler.invoke_out_buf(m_expected_invoke_out_buf);
@@ -337,12 +337,12 @@ TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_process
std::string in_data(256, 'q');
epee::levin::bucket_head2 req_head;
- req_head.m_signature = LEVIN_SIGNATURE;
- req_head.m_cb = in_data.size();
+ req_head.m_signature = SWAP64LE(LEVIN_SIGNATURE);
+ req_head.m_cb = SWAP64LE(in_data.size());
req_head.m_have_to_return_data = true;
- req_head.m_command = expected_command;
- req_head.m_flags = LEVIN_PACKET_REQUEST;
- req_head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ req_head.m_command = SWAP32LE(expected_command);
+ req_head.m_flags = SWAP32LE(LEVIN_PACKET_REQUEST);
+ req_head.m_protocol_version = SWAP32LE(LEVIN_PROTOCOL_VER_1);
std::string buf(reinterpret_cast<const char*>(&req_head), sizeof(req_head));
buf += in_data;
@@ -373,13 +373,13 @@ TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_process
// Check sent response
ASSERT_EQ(expected_out_data, out_data);
- ASSERT_EQ(LEVIN_SIGNATURE, resp_head.m_signature);
- ASSERT_EQ(expected_command, resp_head.m_command);
- ASSERT_EQ(expected_return_code, resp_head.m_return_code);
- ASSERT_EQ(expected_out_data.size(), resp_head.m_cb);
+ ASSERT_EQ(LEVIN_SIGNATURE, SWAP64LE(resp_head.m_signature));
+ ASSERT_EQ(expected_command, SWAP32LE(resp_head.m_command));
+ ASSERT_EQ(expected_return_code, SWAP32LE(resp_head.m_return_code));
+ ASSERT_EQ(expected_out_data.size(), SWAP64LE(resp_head.m_cb));
ASSERT_FALSE(resp_head.m_have_to_return_data);
- ASSERT_EQ(LEVIN_PROTOCOL_VER_1, resp_head.m_protocol_version);
- ASSERT_TRUE(0 != (resp_head.m_flags & LEVIN_PACKET_RESPONSE));
+ ASSERT_EQ(SWAP32LE(LEVIN_PROTOCOL_VER_1), resp_head.m_protocol_version);
+ ASSERT_TRUE(0 != (SWAP32LE(resp_head.m_flags) & LEVIN_PACKET_RESPONSE));
}
TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_processes_handle_read_as_notify)
@@ -392,12 +392,12 @@ TEST_F(positive_test_connection_to_levin_protocol_handler_calls, handler_process
std::string in_data(256, 'e');
epee::levin::bucket_head2 req_head;
- req_head.m_signature = LEVIN_SIGNATURE;
- req_head.m_cb = in_data.size();
+ req_head.m_signature = SWAP64LE(LEVIN_SIGNATURE);
+ req_head.m_cb = SWAP64LE(in_data.size());
req_head.m_have_to_return_data = false;
- req_head.m_command = expected_command;
- req_head.m_flags = LEVIN_PACKET_REQUEST;
- req_head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
+ req_head.m_command = SWAP32LE(expected_command);
+ req_head.m_flags = SWAP32LE(LEVIN_PACKET_REQUEST);
+ req_head.m_protocol_version = SWAP32LE(LEVIN_PROTOCOL_VER_1);
std::string buf(reinterpret_cast<const char*>(&req_head), sizeof(req_head));
buf += in_data;
@@ -618,7 +618,7 @@ TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_two_re
TEST_F(test_levin_protocol_handler__hanle_recv_with_invalid_data, handles_unexpected_response)
{
- m_req_head.m_flags = LEVIN_PACKET_RESPONSE;
+ m_req_head.m_flags = SWAP32LE(LEVIN_PACKET_RESPONSE);
prepare_buf();
ASSERT_FALSE(m_conn->m_protocol_handler.handle_recv(m_buf.data(), m_buf.size()));
diff --git a/tests/unit_tests/net.cpp b/tests/unit_tests/net.cpp
index 9fe43637b..253280d4d 100644
--- a/tests/unit_tests/net.cpp
+++ b/tests/unit_tests/net.cpp
@@ -1042,7 +1042,8 @@ TEST(dandelionpp_map, dropped_connection_remapped)
boost::uuids::random_generator random_uuid{};
std::vector<boost::uuids::uuid> connections{3};
- std::generate(connections.begin(), connections.end(), random_uuid);
+ for (auto &e: connections)
+ e = random_uuid();
std::sort(connections.begin(), connections.end());
// select 3 of 3 outgoing connections
@@ -1072,7 +1073,8 @@ TEST(dandelionpp_map, dropped_connection_remapped)
}
std::map<boost::uuids::uuid, boost::uuids::uuid> mapping;
std::vector<boost::uuids::uuid> in_connections{9};
- std::generate(in_connections.begin(), in_connections.end(), random_uuid);
+ for (auto &e: in_connections)
+ e = random_uuid();
{
std::map<boost::uuids::uuid, std::size_t> used;
std::multimap<boost::uuids::uuid, boost::uuids::uuid> inverse_mapping;
@@ -1151,7 +1153,8 @@ TEST(dandelionpp_map, dropped_connection_remapped)
}
// map 8 new incoming connections across 3 outgoing links
in_connections.resize(18);
- std::generate(in_connections.begin() + 10, in_connections.end(), random_uuid);
+ for (size_t i = 10; i < in_connections.size(); ++i)
+ in_connections[i] = random_uuid();
{
std::map<boost::uuids::uuid, std::size_t> used;
for (const boost::uuids::uuid& connection : in_connections)
@@ -1178,7 +1181,8 @@ TEST(dandelionpp_map, dropped_all_connections)
boost::uuids::random_generator random_uuid{};
std::vector<boost::uuids::uuid> connections{8};
- std::generate(connections.begin(), connections.end(), random_uuid);
+ for (auto &e: connections)
+ e = random_uuid();
std::sort(connections.begin(), connections.end());
// select 3 of 8 outgoing connections
@@ -1207,7 +1211,8 @@ TEST(dandelionpp_map, dropped_all_connections)
}
}
std::vector<boost::uuids::uuid> in_connections{9};
- std::generate(in_connections.begin(), in_connections.end(), random_uuid);
+ for (auto &e: in_connections)
+ e = random_uuid();
{
std::map<boost::uuids::uuid, std::size_t> used;
std::map<boost::uuids::uuid, boost::uuids::uuid> mapping;
@@ -1239,7 +1244,8 @@ TEST(dandelionpp_map, dropped_all_connections)
// select 3 of 30 connections, only 7 should be remapped to new indexes (but all to new uuids)
connections.resize(30);
- std::generate(connections.begin(), connections.end(), random_uuid);
+ for (auto &e: connections)
+ e = random_uuid();
EXPECT_TRUE(mapper.update(connections));
{
std::map<boost::uuids::uuid, std::size_t> used;
diff --git a/tests/unit_tests/output_distribution.cpp b/tests/unit_tests/output_distribution.cpp
index 38f442c59..eec694d1e 100644
--- a/tests/unit_tests/output_distribution.cpp
+++ b/tests/unit_tests/output_distribution.cpp
@@ -93,7 +93,7 @@ bool get_output_distribution(uint64_t amount, uint64_t from, uint64_t to, uint64
crypto::hash get_block_hash(uint64_t height)
{
- crypto::hash hash;
+ crypto::hash hash = crypto::null_hash;
*((uint64_t*)&hash) = height;
return hash;
}
diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py
index 36ff3644f..3bbb8b151 100644
--- a/utils/python-rpc/framework/wallet.py
+++ b/utils/python-rpc/framework/wallet.py
@@ -140,13 +140,14 @@ class Wallet(object):
}
return self.rpc.send_json_rpc_request(create_wallet)
- def get_balance(self, account_index = 0, address_indices = [], all_accounts = False):
+ def get_balance(self, account_index = 0, address_indices = [], all_accounts = False, strict = False):
get_balance = {
'method': 'get_balance',
'params': {
'account_index': account_index,
'address_indices': address_indices,
'all_accounts': all_accounts,
+ 'strict': strict,
},
'jsonrpc': '2.0',
'id': '0'