aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md4
-rw-r--r--contrib/depends/packages/icu4c.mk4
-rw-r--r--contrib/depends/packages/libevent.mk30
-rw-r--r--contrib/depends/packages/packages.mk3
-rw-r--r--contrib/depends/packages/qt.mk10
-rw-r--r--contrib/depends/packages/zlib.mk27
-rw-r--r--contrib/epee/include/storages/parserse_base_utils.h72
-rw-r--r--contrib/epee/include/storages/portable_storage_from_json.h62
-rw-r--r--src/blockchain_db/blockchain_db.h2
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp5
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h2
-rw-r--r--src/blockchain_utilities/blockchain_ancestry.cpp438
-rw-r--r--src/simplewallet/simplewallet.cpp144
-rw-r--r--src/simplewallet/simplewallet.h2
-rw-r--r--src/wallet/wallet2.cpp97
-rw-r--r--src/wallet/wallet2.h20
-rw-r--r--tests/unit_tests/epee_utils.cpp84
-rw-r--r--tests/unit_tests/testdb.h2
18 files changed, 585 insertions, 423 deletions
diff --git a/README.md b/README.md
index 234812f27..0e28c9469 100644
--- a/README.md
+++ b/README.md
@@ -316,13 +316,13 @@ application.
* Open the MSYS shell via the `MSYS2 Shell` shortcut
* Update packages using pacman:
- pacman -Syuu
+ pacman -Syu
* Exit the MSYS shell using Alt+F4
* Edit the properties for the `MSYS2 Shell` shortcut changing "msys2_shell.bat" to "msys2_shell.cmd -mingw64" for 64-bit builds or "msys2_shell.cmd -mingw32" for 32-bit builds
* Restart MSYS shell via modified shortcut and update packages again using pacman:
- pacman -Syuu
+ pacman -Syu
* Install dependencies:
diff --git a/contrib/depends/packages/icu4c.mk b/contrib/depends/packages/icu4c.mk
index 7e092425e..370a02683 100644
--- a/contrib/depends/packages/icu4c.mk
+++ b/contrib/depends/packages/icu4c.mk
@@ -6,7 +6,7 @@ $(package)_sha256_hash=1f912c54035533fb4268809701d65c7468d00e292efbc31e644490845
$(package)_patches=icu-001-dont-build-static-dynamic-twice.patch
define $(package)_set_vars
- $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 --std=gnu++0x -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC"
+ $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 --std=gnu++0x -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC -DENABLE_STATIC=YES -DPGKDATA_MODE=static"
endef
define $(package)_config_cmds
@@ -17,7 +17,7 @@ define $(package)_config_cmds
sh ../source/runConfigureICU Linux &&\
make &&\
cd ../buildb &&\
- sh ../source/$($(package)_autoconf) --enable-static=yes --enable-shared=yes --disable-layoutex --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\
+ sh ../source/$($(package)_autoconf) --enable-static=yes --disable-shared --disable-layout --disable-layoutex --disable-tests --disable-samples --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\
$(MAKE) $($(package)_build_opts)
endef
diff --git a/contrib/depends/packages/libevent.mk b/contrib/depends/packages/libevent.mk
deleted file mode 100644
index 5f622f8e6..000000000
--- a/contrib/depends/packages/libevent.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-package=libevent
-$(package)_version=2.1.8-stable
-$(package)_download_path=https://github.com/libevent/libevent/archive/
-$(package)_file_name=release-$($(package)_version).tar.gz
-$(package)_sha256_hash=316ddb401745ac5d222d7c529ef1eada12f58f6376a66c1118eee803cb70f83d
-
-define $(package)_preprocess_cmds
- ./autogen.sh
-endef
-
-define $(package)_set_vars
- $(package)_config_opts=--disable-shared --disable-openssl --disable-libevent-regress --disable-samples
- $(package)_config_opts_release=--disable-debug-mode
- $(package)_config_opts_linux=--with-pic
-endef
-
-define $(package)_config_cmds
- $($(package)_autoconf)
-endef
-
-define $(package)_build_cmds
- $(MAKE)
-endef
-
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install
-endef
-
-define $(package)_postprocess_cmds
-endef
diff --git a/contrib/depends/packages/packages.mk b/contrib/depends/packages/packages.mk
index b3a5992d0..4800c9936 100644
--- a/contrib/depends/packages/packages.mk
+++ b/contrib/depends/packages/packages.mk
@@ -1,4 +1,4 @@
-packages:=boost openssl libevent zeromq cppzmq zlib expat ldns cppzmq readline libiconv qt hidapi protobuf libusb
+packages:=boost openssl zeromq cppzmq expat ldns cppzmq readline libiconv qt hidapi protobuf libusb
native_packages := native_ccache native_protobuf
darwin_native_packages = native_biplist native_ds_store native_mac_alias
@@ -17,6 +17,5 @@ endif
ifneq ($(build_os),darwin)
darwin_native_packages += native_cctools native_cdrkit native_libdmg-hfsplus
-packages += readline
endif
diff --git a/contrib/depends/packages/qt.mk b/contrib/depends/packages/qt.mk
index bca2926cb..6a6f0e0f7 100644
--- a/contrib/depends/packages/qt.mk
+++ b/contrib/depends/packages/qt.mk
@@ -4,7 +4,6 @@ $(package)_download_path=https://download.qt.io/archive/qt/5.7/5.7.1/submodules
$(package)_suffix=opensource-src-$($(package)_version).tar.gz
$(package)_file_name=qtbase-$($(package)_suffix)
$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410
-$(package)_dependencies=openssl zlib
$(package)_build_subdir=qtbase
$(package)_qt_libs=corelib
$(package)_patches=pidlist_absolute.patch fix_qt_pkgconfig.patch qfixed-coretext.patch
@@ -62,14 +61,14 @@ $(package)_config_opts += -no-xrender
$(package)_config_opts += -nomake examples
$(package)_config_opts += -nomake tests
$(package)_config_opts += -opensource
-$(package)_config_opts += -openssl-linked
+$(package)_config_opts += -no-openssl
$(package)_config_opts += -optimized-qmake
$(package)_config_opts += -pch
$(package)_config_opts += -pkg-config
-$(package)_config_opts += -qt-libpng
-$(package)_config_opts += -qt-libjpeg
+$(package)_config_opts += -no-libpng
+$(package)_config_opts += -no-libjpeg
$(package)_config_opts += -qt-pcre
-$(package)_config_opts += -system-zlib
+$(package)_config_opts += -no-zlib
$(package)_config_opts += -reduce-exports
$(package)_config_opts += -static
$(package)_config_opts += -silent
@@ -124,7 +123,6 @@ define $(package)_config_cmds
export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \
export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \
./configure $($(package)_config_opts) && \
- echo "host_build: QT_CONFIG ~= s/system-zlib/zlib" >> mkspecs/qconfig.pri && \
echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \
$(MAKE) sub-src-clean && \
cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \
diff --git a/contrib/depends/packages/zlib.mk b/contrib/depends/packages/zlib.mk
deleted file mode 100644
index 1600b11a0..000000000
--- a/contrib/depends/packages/zlib.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-package=zlib
-$(package)_version=1.2.11
-$(package)_download_path=https://www.zlib.net
-$(package)_file_name=$(package)-$($(package)_version).tar.gz
-$(package)_sha256_hash=c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1
-
-define $(package)_set_vars
-$(package)_build_opts= CC="$($(package)_cc)"
-$(package)_build_opts+=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC"
-$(package)_build_opts+=RANLIB="$($(package)_ranlib)"
-$(package)_build_opts+=AR="$($(package)_ar)"
-$(package)_build_opts_darwin+=AR="$($(package)_libtool)"
-$(package)_build_opts_darwin+=ARFLAGS="-o"
-endef
-
-define $(package)_config_cmds
- ./configure --static --prefix=$(host_prefix)
-endef
-
-define $(package)_build_cmds
- $(MAKE) $($(package)_build_opts) libz.a
-endef
-
-define $(package)_stage_cmds
- $(MAKE) DESTDIR=$($(package)_staging_dir) install $($(package)_build_opts)
-endef
-
diff --git a/contrib/epee/include/storages/parserse_base_utils.h b/contrib/epee/include/storages/parserse_base_utils.h
index d73fbde3a..69b650cd4 100644
--- a/contrib/epee/include/storages/parserse_base_utils.h
+++ b/contrib/epee/include/storages/parserse_base_utils.h
@@ -29,6 +29,7 @@
#pragma once
#include <algorithm>
+#include <boost/utility/string_ref.hpp>
namespace epee
{
@@ -36,6 +37,40 @@ namespace misc_utils
{
namespace parse
{
+ // 1: digit
+ // 2: .eE (floating point)
+ // 4: alpha
+ // 8: whitespace
+ // 16: allowed in float but doesn't necessarily mean it's a float
+ static const constexpr uint8_t lut[256]={
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, // 16
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
+ 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 18, 0, // 48
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 0, 0, 0, 0, // 64
+ 0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 80
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 96
+ 0, 4, 4, 4, 4, 22, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 112
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, // 128
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ inline bool isspace(char c)
+ {
+ return lut[(uint8_t)c] & 8;
+ }
+
+ inline bool isdigit(char c)
+ {
+ return lut[(uint8_t)c] & 1;
+ }
+
inline std::string transform_to_escape_sequence(const std::string& src)
{
static const char escaped[] = "\b\f\n\r\t\v\"\\/";
@@ -159,25 +194,34 @@ namespace misc_utils
return false;
}
}
- inline void match_number2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val, bool& is_float_val, bool& is_signed_val)
+ inline void match_number2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val, bool& is_float_val, bool& is_signed_val)
{
val.clear();
- is_float_val = false;
- for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
+ uint8_t float_flag = 0;
+ is_signed_val = false;
+ size_t chars = 0;
+ std::string::const_iterator it = star_end_string;
+ if (it != buf_end && *it == '-')
+ {
+ is_signed_val = true;
+ ++chars;
+ ++it;
+ }
+ for(;it != buf_end;it++)
{
- if(isdigit(*it) || (it == star_end_string && *it == '-') || (val.size() && *it == '.' ) || (is_float_val && (*it == 'e' || *it == 'E' || *it == '-' || *it == '+' )) )
+ const uint8_t flags = lut[(uint8_t)*it];
+ if (flags & 16)
{
- if(!val.size() && *it == '-')
- is_signed_val = true;
- if(*it == '.' )
- is_float_val = true;
- val.push_back(*it);
+ float_flag |= flags;
+ ++chars;
}
else
{
+ val = boost::string_ref(&*star_end_string, chars);
if(val.size())
{
star_end_string = --it;
+ is_float_val = !!(float_flag & 2);
return;
}
else
@@ -186,7 +230,7 @@ namespace misc_utils
}
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
}
- inline bool match_number(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ inline bool match_number(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
{
try
{
@@ -199,15 +243,15 @@ namespace misc_utils
return false;
}
}
- inline void match_word2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ inline void match_word2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
{
val.clear();
for(std::string::const_iterator it = star_end_string;it != buf_end;it++)
{
- if(!isalpha(*it))
+ if (!(lut[(uint8_t)*it] & 4))
{
- val.assign(star_end_string, it);
+ val = boost::string_ref(&*star_end_string, std::distance(star_end_string, it));
if(val.size())
{
star_end_string = --it;
@@ -218,7 +262,7 @@ namespace misc_utils
}
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
}
- inline bool match_word(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
+ inline bool match_word(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, boost::string_ref& val)
{
try
{
diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h
index 0307b732c..3e3052541 100644
--- a/contrib/epee/include/storages/portable_storage_from_json.h
+++ b/contrib/epee/include/storages/portable_storage_from_json.h
@@ -39,7 +39,7 @@ namespace epee
{
namespace json
{
-#define CHECK_ISSPACE() if(!isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
+#define CHECK_ISSPACE() if(!epee::misc_utils::parse::isspace(*it)){ ASSERT_MES_AND_THROW("Wrong JSON character at: " << std::string(it, buf_end));}
/*inline void parse_error()
{
@@ -114,11 +114,11 @@ namespace epee
std::string val;
match_string2(it, buf_end, val);
//insert text value
- stg.set_value(name, val, current_section);
+ stg.set_value(name, std::move(val), current_section);
state = match_state_wonder_after_value;
- }else if (isdigit(*it) || *it == '-')
+ }else if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
{//just a named number value started
- std::string val;
+ boost::string_ref val;
bool is_v_float = false;bool is_signed = false;
match_number2(it, buf_end, val, is_v_float, is_signed);
if(!is_v_float)
@@ -126,27 +126,27 @@ namespace epee
if(is_signed)
{
errno = 0;
- int64_t nval = strtoll(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ int64_t nval = strtoll(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
stg.set_value(name, nval, current_section);
}else
{
errno = 0;
- uint64_t nval = strtoull(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ uint64_t nval = strtoull(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
stg.set_value(name, nval, current_section);
}
}else
{
errno = 0;
- double nval = strtod(val.c_str(), NULL);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ double nval = strtod(val.data(), NULL);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
stg.set_value(name, nval, current_section);
}
state = match_state_wonder_after_value;
}else if(isalpha(*it) )
{// could be null, true or false
- std::string word;
+ boost::string_ref word;
match_word2(it, buf_end, word);
if(boost::iequals(word, "null"))
{
@@ -203,13 +203,13 @@ namespace epee
//mean array of strings
std::string val;
match_string2(it, buf_end, val);
- h_array = stg.insert_first_value(name, val, current_section);
+ h_array = stg.insert_first_value(name, std::move(val), current_section);
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry");
state = match_state_array_after_value;
array_md = array_mode_string;
- }else if (isdigit(*it) || *it == '-')
+ }else if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
{//array of numbers value started
- std::string val;
+ boost::string_ref val;
bool is_v_float = false;bool is_signed_val = false;
match_number2(it, buf_end, val, is_v_float, is_signed_val);
if(!is_v_float)
@@ -217,22 +217,22 @@ namespace epee
if (is_signed_val)
{
errno = 0;
- int64_t nval = strtoll(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ int64_t nval = strtoll(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
h_array = stg.insert_first_value(name, nval, current_section);
}else
{
errno = 0;
- uint64_t nval = strtoull(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ uint64_t nval = strtoull(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
h_array = stg.insert_first_value(name, nval, current_section);
}
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
}else
{
errno = 0;
- double nval = strtod(val.c_str(), NULL);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ double nval = strtod(val.data(), NULL);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
h_array = stg.insert_first_value(name, nval, current_section);
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values section entry");
}
@@ -245,7 +245,7 @@ namespace epee
state = match_state_wonder_after_value;
}else if(isalpha(*it) )
{// array of booleans
- std::string word;
+ boost::string_ref word;
match_word2(it, buf_end, word);
if(boost::iequals(word, "true"))
{
@@ -291,15 +291,15 @@ namespace epee
{
std::string val;
match_string2(it, buf_end, val);
- bool res = stg.insert_next_value(h_array, val);
+ bool res = stg.insert_next_value(h_array, std::move(val));
CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values");
state = match_state_array_after_value;
}else CHECK_ISSPACE();
break;
case array_mode_numbers:
- if (isdigit(*it) || *it == '-')
+ if (epee::misc_utils::parse::isdigit(*it) || *it == '-')
{//array of numbers value started
- std::string val;
+ boost::string_ref val;
bool is_v_float = false;bool is_signed_val = false;
match_number2(it, buf_end, val, is_v_float, is_signed_val);
bool insert_res = false;
@@ -308,21 +308,21 @@ namespace epee
if (is_signed_val)
{
errno = 0;
- int64_t nval = strtoll(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ int64_t nval = strtoll(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
insert_res = stg.insert_next_value(h_array, nval);
}else
{
errno = 0;
- uint64_t nval = strtoull(val.c_str(), NULL, 10);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ uint64_t nval = strtoull(val.data(), NULL, 10);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
insert_res = stg.insert_next_value(h_array, nval);
}
}else
{
errno = 0;
- double nval = strtod(val.c_str(), NULL);
- if (errno) throw std::runtime_error("Invalid number: " + val);
+ double nval = strtod(val.data(), NULL);
+ if (errno) throw std::runtime_error("Invalid number: " + std::string(val));
insert_res = stg.insert_next_value(h_array, nval);
}
CHECK_AND_ASSERT_THROW_MES(insert_res, "Failed to insert next value");
@@ -333,7 +333,7 @@ namespace epee
case array_mode_booleans:
if(isalpha(*it) )
{// array of booleans
- std::string word;
+ boost::string_ref word;
match_word2(it, buf_end, word);
if(boost::iequals(word, "true"))
{
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 5c80bfe4a..fe61aabd8 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1258,7 +1258,7 @@ public:
*
* @return the requested output data
*/
- virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const = 0;
+ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt = true) const = 0;
/**
* @brief gets an output's tx hash and index
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 833d6bd05..2b5fa7fd9 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -2536,7 +2536,7 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
return num_elems;
}
-output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index) const
+output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -2563,7 +2563,8 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint6
{
const pre_rct_outkey *okp = (const pre_rct_outkey *)v.mv_data;
memcpy(&ret, &okp->data, sizeof(pre_rct_output_data_t));;
- ret.commitment = rct::zeroCommit(amount);
+ if (include_commitmemt)
+ ret.commitment = rct::zeroCommit(amount);
}
TXN_POSTFIX_RDONLY();
return ret;
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 3e6e754d2..a60956ab1 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -242,7 +242,7 @@ public:
virtual uint64_t get_num_outputs(const uint64_t& amount) const;
- virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const;
+ virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const;
virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) const;
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
diff --git a/src/blockchain_utilities/blockchain_ancestry.cpp b/src/blockchain_utilities/blockchain_ancestry.cpp
index e01a8892c..a64ce160a 100644
--- a/src/blockchain_utilities/blockchain_ancestry.cpp
+++ b/src/blockchain_utilities/blockchain_ancestry.cpp
@@ -51,6 +51,8 @@ using namespace epee;
using namespace cryptonote;
static bool stop_requested = false;
+static uint64_t cached_txes = 0, cached_blocks = 0, cached_outputs = 0, total_txes = 0, total_blocks = 0, total_outputs = 0;
+static bool opt_cache_outputs = false, opt_cache_txes = false, opt_cache_blocks = false;
struct ancestor
{
@@ -137,6 +139,8 @@ struct ancestry_state_t
std::unordered_map<crypto::hash, ::tx_data_t> tx_cache;
std::vector<cryptonote::block> block_cache;
+ ancestry_state_t(): height(0) {}
+
template <typename t_archive> void serialize(t_archive &a, const unsigned int ver)
{
a & height;
@@ -219,6 +223,113 @@ static std::unordered_set<ancestor> get_ancestry(const std::unordered_map<crypto
return i->second;
}
+static bool get_block_from_height(ancestry_state_t &state, BlockchainDB *db, uint64_t height, cryptonote::block &b)
+{
+ ++total_blocks;
+ if (state.block_cache.size() > height && !state.block_cache[height].miner_tx.vin.empty())
+ {
+ ++cached_blocks;
+ b = state.block_cache[height];
+ return true;
+ }
+ cryptonote::blobdata bd = db->get_block_blob_from_height(height);
+ if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
+ {
+ LOG_PRINT_L0("Bad block from db");
+ return false;
+ }
+ if (opt_cache_blocks)
+ {
+ state.block_cache.resize(height + 1);
+ state.block_cache[height] = b;
+ }
+ return true;
+}
+
+static bool get_transaction(ancestry_state_t &state, BlockchainDB *db, const crypto::hash &txid, ::tx_data_t &tx_data)
+{
+ std::unordered_map<crypto::hash, ::tx_data_t>::const_iterator i = state.tx_cache.find(txid);
+ ++total_txes;
+ if (i != state.tx_cache.end())
+ {
+ ++cached_txes;
+ tx_data = i->second;
+ return true;
+ }
+
+ cryptonote::blobdata bd;
+ if (!db->get_pruned_tx_blob(txid, bd))
+ {
+ LOG_PRINT_L0("Failed to get txid " << txid << " from db");
+ return false;
+ }
+ cryptonote::transaction tx;
+ if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
+ {
+ LOG_PRINT_L0("Bad tx: " << txid);
+ return false;
+ }
+ tx_data = ::tx_data_t(tx);
+ if (opt_cache_txes)
+ state.tx_cache.insert(std::make_pair(txid, tx_data));
+ return true;
+}
+
+static bool get_output_txid(ancestry_state_t &state, BlockchainDB *db, uint64_t amount, uint64_t offset, crypto::hash &txid)
+{
+ ++total_outputs;
+ std::unordered_map<ancestor, crypto::hash>::const_iterator i = state.output_cache.find({amount, offset});
+ if (i != state.output_cache.end())
+ {
+ ++cached_outputs;
+ txid = i->second;
+ return true;
+ }
+
+ const output_data_t od = db->get_output_key(amount, offset, false);
+ cryptonote::block b;
+ if (!get_block_from_height(state, db, od.height, b))
+ return false;
+
+ for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
+ {
+ if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
+ {
+ const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
+ if (txout.key == od.pubkey)
+ {
+ txid = cryptonote::get_transaction_hash(b.miner_tx);
+ if (opt_cache_outputs)
+ state.output_cache.insert(std::make_pair(ancestor{amount, offset}, txid));
+ return true;
+ }
+ }
+ else
+ {
+ LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
+ return false;
+ }
+ }
+ for (const crypto::hash &block_txid: b.tx_hashes)
+ {
+ ::tx_data_t tx_data3;
+ if (!get_transaction(state, db, block_txid, tx_data3))
+ return false;
+
+ for (size_t out = 0; out < tx_data3.vout.size(); ++out)
+ {
+ if (tx_data3.vout[out] == od.pubkey)
+ {
+ txid = block_txid;
+ if (opt_cache_outputs)
+ state.output_cache.insert(std::make_pair(ancestor{amount, offset}, txid));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
int main(int argc, char* argv[])
{
TRY_ENTRY();
@@ -243,12 +354,13 @@ int main(int argc, char* argv[])
"database", available_dbs.c_str(), default_db_type
};
const command_line::arg_descriptor<std::string> arg_txid = {"txid", "Get ancestry for this txid", ""};
+ const command_line::arg_descriptor<std::string> arg_output = {"output", "Get ancestry for this output (amount/offset format)", ""};
const command_line::arg_descriptor<uint64_t> arg_height = {"height", "Get ancestry for all txes at this height", 0};
- const command_line::arg_descriptor<bool> arg_all = {"all", "Include the whole chain", false};
+ const command_line::arg_descriptor<bool> arg_refresh = {"refresh", "Refresh the whole chain first", false};
const command_line::arg_descriptor<bool> arg_cache_outputs = {"cache-outputs", "Cache outputs (memory hungry)", false};
const command_line::arg_descriptor<bool> arg_cache_txes = {"cache-txes", "Cache txes (memory hungry)", false};
const command_line::arg_descriptor<bool> arg_cache_blocks = {"cache-blocks", "Cache blocks (memory hungry)", false};
- const command_line::arg_descriptor<bool> arg_include_coinbase = {"include-coinbase", "Including coinbase tx", false};
+ const command_line::arg_descriptor<bool> arg_include_coinbase = {"include-coinbase", "Including coinbase tx in per height average", false};
const command_line::arg_descriptor<bool> arg_show_cache_stats = {"show-cache-stats", "Show cache statistics", false};
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
@@ -257,8 +369,9 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, arg_log_level);
command_line::add_arg(desc_cmd_sett, arg_database);
command_line::add_arg(desc_cmd_sett, arg_txid);
+ command_line::add_arg(desc_cmd_sett, arg_output);
command_line::add_arg(desc_cmd_sett, arg_height);
- command_line::add_arg(desc_cmd_sett, arg_all);
+ command_line::add_arg(desc_cmd_sett, arg_refresh);
command_line::add_arg(desc_cmd_sett, arg_cache_outputs);
command_line::add_arg(desc_cmd_sett, arg_cache_txes);
command_line::add_arg(desc_cmd_sett, arg_cache_blocks);
@@ -300,20 +413,22 @@ int main(int argc, char* argv[])
bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
std::string opt_txid_string = command_line::get_arg(vm, arg_txid);
+ std::string opt_output_string = command_line::get_arg(vm, arg_output);
uint64_t opt_height = command_line::get_arg(vm, arg_height);
- bool opt_all = command_line::get_arg(vm, arg_all);
- bool opt_cache_outputs = command_line::get_arg(vm, arg_cache_outputs);
- bool opt_cache_txes = command_line::get_arg(vm, arg_cache_txes);
- bool opt_cache_blocks = command_line::get_arg(vm, arg_cache_blocks);
+ bool opt_refresh = command_line::get_arg(vm, arg_refresh);
+ opt_cache_outputs = command_line::get_arg(vm, arg_cache_outputs);
+ opt_cache_txes = command_line::get_arg(vm, arg_cache_txes);
+ opt_cache_blocks = command_line::get_arg(vm, arg_cache_blocks);
bool opt_include_coinbase = command_line::get_arg(vm, arg_include_coinbase);
bool opt_show_cache_stats = command_line::get_arg(vm, arg_show_cache_stats);
- if ((!opt_txid_string.empty()) + !!opt_height + !!opt_all > 1)
+ if ((!opt_txid_string.empty()) + !!opt_height + !opt_output_string.empty() > 1)
{
- std::cerr << "Only one of --txid, --height and --all can be given" << std::endl;
+ std::cerr << "Only one of --txid, --height, --output can be given" << std::endl;
return 1;
}
crypto::hash opt_txid = crypto::null_hash;
+ uint64_t output_amount = 0, output_offset = 0;
if (!opt_txid_string.empty())
{
if (!epee::string_tools::hex_to_pod(opt_txid_string, opt_txid))
@@ -322,6 +437,14 @@ int main(int argc, char* argv[])
return 1;
}
}
+ else if (!opt_output_string.empty())
+ {
+ if (sscanf(opt_output_string.c_str(), "%" SCNu64 "/%" SCNu64, &output_amount, &output_offset) != 2)
+ {
+ std::cerr << "Invalid output" << std::endl;
+ return 1;
+ }
+ }
std::string db_type = command_line::get_arg(vm, arg_database);
if (!cryptonote::blockchain_valid_db_type(db_type))
@@ -372,37 +495,36 @@ int main(int argc, char* argv[])
std::vector<crypto::hash> start_txids;
- // forward method
- if (opt_all)
- {
- uint64_t cached_txes = 0, cached_blocks = 0, cached_outputs = 0, total_txes = 0, total_blocks = 0, total_outputs = 0;
- ancestry_state_t state;
+ ancestry_state_t state;
- const std::string state_file_path = (boost::filesystem::path(opt_data_dir) / "ancestry-state.bin").string();
- LOG_PRINT_L0("Loading state data from " << state_file_path);
- std::ifstream state_data_in;
- state_data_in.open(state_file_path, std::ios_base::binary | std::ios_base::in);
- if (!state_data_in.fail())
+ const std::string state_file_path = (boost::filesystem::path(opt_data_dir) / "ancestry-state.bin").string();
+ LOG_PRINT_L0("Loading state data from " << state_file_path);
+ std::ifstream state_data_in;
+ state_data_in.open(state_file_path, std::ios_base::binary | std::ios_base::in);
+ if (!state_data_in.fail())
+ {
+ try
{
- try
- {
- boost::archive::portable_binary_iarchive a(state_data_in);
- a >> state;
- }
- catch (const std::exception &e)
- {
- MERROR("Failed to load state data from " << state_file_path << ", restarting from scratch");
- state = ancestry_state_t();
- }
- state_data_in.close();
+ boost::archive::portable_binary_iarchive a(state_data_in);
+ a >> state;
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Failed to load state data from " << state_file_path << ", restarting from scratch");
+ state = ancestry_state_t();
}
+ state_data_in.close();
+ }
- tools::signal_handler::install([](int type) {
- stop_requested = true;
- });
+ tools::signal_handler::install([](int type) {
+ stop_requested = true;
+ });
+ // forward method
+ const uint64_t db_height = db->height();
+ if (opt_refresh)
+ {
MINFO("Starting from height " << state.height);
- const uint64_t db_height = db->height();
state.block_cache.reserve(db_height);
for (uint64_t h = state.height; h < db_height; ++h)
{
@@ -464,113 +586,20 @@ int main(int argc, char* argv[])
{
for (size_t ring = 0; ring < tx_data.vin.size(); ++ring)
{
- if (1)
+ const uint64_t amount = tx_data.vin[ring].first;
+ const std::vector<uint64_t> &absolute_offsets = tx_data.vin[ring].second;
+ for (uint64_t offset: absolute_offsets)
{
- const uint64_t amount = tx_data.vin[ring].first;
- const std::vector<uint64_t> &absolute_offsets = tx_data.vin[ring].second;
- for (uint64_t offset: absolute_offsets)
+ add_ancestry(state.ancestry, txid, ancestor{amount, offset});
+ // find the tx which created this output
+ bool found = false;
+ crypto::hash output_txid;
+ if (!get_output_txid(state, db, amount, offset, output_txid))
{
- const output_data_t od = db->get_output_key(amount, offset);
- add_ancestry(state.ancestry, txid, ancestor{amount, offset});
- cryptonote::block b;
- ++total_blocks;
- if (state.block_cache.size() > od.height && !state.block_cache[od.height].miner_tx.vin.empty())
- {
- ++cached_blocks;
- b = state.block_cache[od.height];
- }
- else
- {
- cryptonote::blobdata bd = db->get_block_blob_from_height(od.height);
- if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
- {
- LOG_PRINT_L0("Bad block from db");
- return 1;
- }
- if (opt_cache_blocks)
- {
- state.block_cache.resize(od.height + 1);
- state.block_cache[od.height] = b;
- }
- }
- // find the tx which created this output
- bool found = false;
- std::unordered_map<ancestor, crypto::hash>::const_iterator i = state.output_cache.find({amount, offset});
- ++total_outputs;
- if (i != state.output_cache.end())
- {
- ++cached_outputs;
- add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, i->second));
- found = true;
- }
- else for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
- {
- if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
- {
- const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
- if (txout.key == od.pubkey)
- {
- found = true;
- add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, cryptonote::get_transaction_hash(b.miner_tx)));
- if (opt_cache_outputs)
- state.output_cache.insert(std::make_pair(ancestor{amount, offset}, cryptonote::get_transaction_hash(b.miner_tx)));
- break;
- }
- }
- else
- {
- LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
- return 1;
- }
- }
- for (const crypto::hash &block_txid: b.tx_hashes)
- {
- if (found)
- break;
- ::tx_data_t tx_data2;
- std::unordered_map<crypto::hash, ::tx_data_t>::const_iterator i = state.tx_cache.find(block_txid);
- ++total_txes;
- if (i != state.tx_cache.end())
- {
- ++cached_txes;
- tx_data2 = i->second;
- }
- else
- {
- cryptonote::blobdata bd;
- if (!db->get_pruned_tx_blob(block_txid, bd))
- {
- LOG_PRINT_L0("Failed to get txid " << block_txid << " from db");
- return 1;
- }
- cryptonote::transaction tx;
- if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
- {
- LOG_PRINT_L0("Bad tx: " << block_txid);
- return 1;
- }
- tx_data2 = ::tx_data_t(tx);
- if (opt_cache_txes)
- state.tx_cache.insert(std::make_pair(block_txid, tx_data2));
- }
- for (size_t out = 0; out < tx_data2.vout.size(); ++out)
- {
- if (tx_data2.vout[out] == od.pubkey)
- {
- found = true;
- add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, block_txid));
- if (opt_cache_outputs)
- state.output_cache.insert(std::make_pair(ancestor{amount, offset}, block_txid));
- break;
- }
- }
- }
- if (!found)
- {
- LOG_PRINT_L0("Output originating transaction not found");
- return 1;
- }
+ LOG_PRINT_L0("Output originating transaction not found");
+ return 1;
}
+ add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, output_txid));
}
}
}
@@ -581,10 +610,6 @@ int main(int argc, char* argv[])
if (!txids.empty())
{
std::string stats_msg;
- if (opt_show_cache_stats)
- stats_msg = std::string(", cache: txes ") + std::to_string(cached_txes*100./total_txes)
- + ", blocks " + std::to_string(cached_blocks*100./total_blocks) + ", outputs "
- + std::to_string(cached_outputs*100./total_outputs);
MINFO("Height " << h << ": " << (block_ancestry_size / txids.size()) << " average over " << txids.size() << stats_msg);
}
state.height = h;
@@ -608,14 +633,30 @@ int main(int argc, char* argv[])
}
state_data_out.close();
}
-
- goto done;
+ }
+ else
+ {
+ if (state.height < db_height)
+ {
+ MWARNING("The state file is only built up to height " << state.height << ", but the blockchain reached height " << db_height);
+ MWARNING("You may want to run with --refresh if you want to get ancestry for newer data");
+ }
}
if (!opt_txid_string.empty())
{
start_txids.push_back(opt_txid);
}
+ else if (!opt_output_string.empty())
+ {
+ crypto::hash txid;
+ if (!get_output_txid(state, db, output_amount, output_offset, txid))
+ {
+ LOG_PRINT_L0("Output not found in db");
+ return 1;
+ }
+ start_txids.push_back(txid);
+ }
else
{
const cryptonote::blobdata bd = db->get_block_blob_from_height(opt_height);
@@ -648,108 +689,40 @@ int main(int argc, char* argv[])
const crypto::hash txid = txids.front();
txids.pop_front();
- cryptonote::blobdata bd;
- if (!db->get_pruned_tx_blob(txid, bd))
- {
- LOG_PRINT_L0("Failed to get txid " << txid << " from db");
- return 1;
- }
- cryptonote::transaction tx;
- if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
- {
- LOG_PRINT_L0("Bad tx: " << txid);
+ if (stop_requested)
+ goto done;
+
+ ::tx_data_t tx_data2;
+ if (!get_transaction(state, db, txid, tx_data2))
return 1;
- }
- const bool coinbase = tx.vin.size() == 1 && tx.vin[0].type() == typeid(cryptonote::txin_gen);
+
+ const bool coinbase = tx_data2.coinbase;
if (coinbase)
continue;
- for (size_t ring = 0; ring < tx.vin.size(); ++ring)
+ for (size_t ring = 0; ring < tx_data2.vin.size(); ++ring)
{
- if (tx.vin[ring].type() == typeid(cryptonote::txin_to_key))
{
- const cryptonote::txin_to_key &txin = boost::get<cryptonote::txin_to_key>(tx.vin[ring]);
- const uint64_t amount = txin.amount;
- auto absolute_offsets = cryptonote::relative_output_offsets_to_absolute(txin.key_offsets);
+ const uint64_t amount = tx_data2.vin[ring].first;
+ auto absolute_offsets = tx_data2.vin[ring].second;
for (uint64_t offset: absolute_offsets)
{
add_ancestor(ancestry, amount, offset);
- const output_data_t od = db->get_output_key(amount, offset);
- bd = db->get_block_blob_from_height(od.height);
- cryptonote::block b;
- if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
- {
- LOG_PRINT_L0("Bad block from db");
- return 1;
- }
+
// find the tx which created this output
bool found = false;
- for (size_t out = 0; out < b.miner_tx.vout.size(); ++out)
- {
- if (b.miner_tx.vout[out].target.type() == typeid(cryptonote::txout_to_key))
- {
- const auto &txout = boost::get<cryptonote::txout_to_key>(b.miner_tx.vout[out].target);
- if (txout.key == od.pubkey)
- {
- found = true;
- txids.push_back(cryptonote::get_transaction_hash(b.miner_tx));
- MDEBUG("adding txid: " << cryptonote::get_transaction_hash(b.miner_tx));
- break;
- }
- }
- else
- {
- LOG_PRINT_L0("Bad vout type in txid " << cryptonote::get_transaction_hash(b.miner_tx));
- return 1;
- }
- }
- for (const crypto::hash &block_txid: b.tx_hashes)
- {
- if (found)
- break;
- if (!db->get_pruned_tx_blob(block_txid, bd))
- {
- LOG_PRINT_L0("Failed to get txid " << block_txid << " from db");
- return 1;
- }
- cryptonote::transaction tx2;
- if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx2))
- {
- LOG_PRINT_L0("Bad tx: " << block_txid);
- return 1;
- }
- for (size_t out = 0; out < tx2.vout.size(); ++out)
- {
- if (tx2.vout[out].target.type() == typeid(cryptonote::txout_to_key))
- {
- const auto &txout = boost::get<cryptonote::txout_to_key>(tx2.vout[out].target);
- if (txout.key == od.pubkey)
- {
- found = true;
- txids.push_back(block_txid);
- MDEBUG("adding txid: " << block_txid);
- break;
- }
- }
- else
- {
- LOG_PRINT_L0("Bad vout type in txid " << block_txid);
- return 1;
- }
- }
- }
- if (!found)
+ crypto::hash output_txid;
+ if (!get_output_txid(state, db, amount, offset, output_txid))
{
LOG_PRINT_L0("Output originating transaction not found");
return 1;
}
+
+ add_ancestry(state.ancestry, txid, get_ancestry(state.ancestry, output_txid));
+ txids.push_back(output_txid);
+ MDEBUG("adding txid: " << output_txid);
}
}
- else
- {
- LOG_PRINT_L0("Bad vin type in txid " << txid);
- return 1;
- }
}
}
@@ -762,6 +735,13 @@ int main(int argc, char* argv[])
done:
core_storage->deinit();
+
+ if (opt_show_cache_stats)
+ MINFO("cache: txes " << std::to_string(cached_txes*100./total_txes)
+ << "%, blocks " << std::to_string(cached_blocks*100./total_blocks)
+ << "%, outputs " << std::to_string(cached_outputs*100./total_outputs)
+ << "%");
+
return 0;
CATCH_ENTRY("Depth query error", 1);
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 1689cb170..c3f06e831 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -113,6 +113,14 @@ typedef cryptonote::simple_wallet sw;
#define PRINT_USAGE(usage_help) fail_msg_writer() << boost::format(tr("usage: %s")) % usage_help;
+#define LONG_PAYMENT_ID_SUPPORT_CHECK() \
+ do { \
+ if (!m_long_payment_id_support) { \
+ fail_msg_writer() << tr("Long payment IDs are obsolete. Use --long-payment-id-support if you really must use one."); \
+ return true; \
+ } \
+ } while(0)
+
enum TransferType {
Transfer,
TransferLocked,
@@ -141,6 +149,7 @@ namespace
const command_line::arg_descriptor<bool> arg_create_address_file = {"create-address-file", sw::tr("Create an address file for new wallets"), false};
const command_line::arg_descriptor<std::string> arg_subaddress_lookahead = {"subaddress-lookahead", tools::wallet2::tr("Set subaddress lookahead sizes to <major>:<minor>"), ""};
const command_line::arg_descriptor<bool> arg_use_english_language_names = {"use-english-language-names", sw::tr("Display English language names"), false};
+ const command_line::arg_descriptor<bool> arg_long_payment_id_support = {"long-payment-id-support", sw::tr("Support obsolete long (unencrypted) payment ids"), false};
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
@@ -151,12 +160,12 @@ namespace
const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
const char* USAGE_PAYMENT_ID("payment_id");
const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]");
- const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id>]");
- const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id>]");
- const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]");
- const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]");
- const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]");
- const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]");
+ const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
+ const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
+ const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id (obsolete)>]");
const char* USAGE_SIGN_TRANSFER("sign_transfer [export_raw]");
const char* USAGE_SET_LOG("set_log <level>|{+,-,}<categories>");
const char* USAGE_ACCOUNT("account\n"
@@ -231,12 +240,15 @@ namespace
const char* USAGE_VERSION("version");
const char* USAGE_HELP("help [<command>]");
- std::string input_line(const std::string& prompt)
+ std::string input_line(const std::string& prompt, bool yesno = false)
{
#ifdef HAVE_READLINE
rdln::suspend_readline pause_readline;
#endif
std::cout << prompt;
+ if (yesno)
+ std::cout << " (Y/Yes/N/No)";
+ std::cout << ": " << std::flush;
std::string buf;
#ifdef _WIN32
@@ -248,12 +260,12 @@ namespace
return epee::string_tools::trim(buf);
}
- epee::wipeable_string input_secure_line(const std::string& prompt)
+ epee::wipeable_string input_secure_line(const char *prompt)
{
#ifdef HAVE_READLINE
rdln::suspend_readline pause_readline;
#endif
- auto pwd_container = tools::password_container::prompt(false, prompt.c_str(), false);
+ auto pwd_container = tools::password_container::prompt(false, prompt, false);
if (!pwd_container)
{
MERROR("Failed to read secure line");
@@ -426,10 +438,10 @@ namespace
<< ", " << dnssec_str << std::endl
<< sw::tr(" Monero Address = ") << addresses[0]
<< std::endl
- << sw::tr("Is this OK? (Y/n) ")
+ << sw::tr("Is this OK?")
;
// prompt the user for confirmation given the dns query and dnssec status
- std::string confirm_dns_ok = input_line(prompt.str());
+ std::string confirm_dns_ok = input_line(prompt.str(), true);
if (std::cin.eof())
{
return {};
@@ -597,7 +609,7 @@ namespace
fail_msg_writer() << boost::format(sw::tr("File %s likely stores wallet private keys! Use a different file name.")) % filename;
return false;
}
- return command_line::is_yes(input_line((boost::format(sw::tr("File %s already exists. Are you sure to overwrite it? (Y/Yes/N/No): ")) % filename).str()));
+ return command_line::is_yes(input_line((boost::format(sw::tr("File %s already exists. Are you sure to overwrite it?")) % filename).str(), true));
}
return true;
}
@@ -861,6 +873,8 @@ bool simple_wallet::change_password(const std::vector<std::string> &args)
bool simple_wallet::payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
crypto::hash payment_id;
if (args.size() > 0)
{
@@ -2223,6 +2237,8 @@ bool simple_wallet::set_refresh_type(const std::vector<std::string> &args/* = st
bool simple_wallet::set_confirm_missing_payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
@@ -2783,7 +2799,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("rescan_bc",
boost::bind(&simple_wallet::rescan_blockchain, this, _1),
tr(USAGE_RESCAN_BC),
- tr("Rescan the blockchain from scratch, losing any information which can not be recovered from the blockchain itself."));
+ tr("Rescan the blockchain from scratch. If \"hard\" is specified, you will lose any information which can not be recovered from the blockchain itself."));
m_cmd_binder.set_handler("set_tx_note",
boost::bind(&simple_wallet::set_tx_note, this, _1),
tr(USAGE_SET_TX_NOTE),
@@ -2848,7 +2864,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("payment_id",
boost::bind(&simple_wallet::payment_id, this, _1),
tr(USAGE_PAYMENT_ID),
- tr("Generate a new random full size payment id. These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids."));
+ tr("Generate a new random full size payment id (obsolete). These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids."));
m_cmd_binder.set_handler("fee",
boost::bind(&simple_wallet::print_fee_info, this, _1),
tr("Print the information about the current fee and transaction backlog."));
@@ -3154,9 +3170,9 @@ bool simple_wallet::ask_wallet_create_if_needed()
LOG_PRINT_L3("User asked to specify wallet file name.");
wallet_path = input_line(
tr(m_restoring ? "Specify a new wallet file name for your restored wallet (e.g., MyWallet).\n"
- "Wallet file name (or Ctrl-C to quit): " :
+ "Wallet file name (or Ctrl-C to quit)" :
"Specify wallet file name (e.g., MyWallet). If the wallet doesn't exist, it will be created.\n"
- "Wallet file name (or Ctrl-C to quit): ")
+ "Wallet file name (or Ctrl-C to quit)")
);
if(std::cin.eof())
{
@@ -3203,7 +3219,7 @@ bool simple_wallet::ask_wallet_create_if_needed()
if (!m_restoring)
{
message_writer() << tr("No wallet found with that name. Confirm creation of new wallet named: ") << wallet_path;
- confirm_creation = input_line(tr("(Y/Yes/N/No): "));
+ confirm_creation = input_line("", true);
if(std::cin.eof())
{
LOG_ERROR("Unexpected std::cin.eof() - Exited simple_wallet::ask_wallet_create_if_needed()");
@@ -3412,7 +3428,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_view_key;
// parse address
- std::string address_string = input_line("Standard address: ");
+ std::string address_string = input_line("Standard address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3432,7 +3448,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse view secret key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
@@ -3467,7 +3483,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_spend_key;
// parse spend secret key
- epee::wipeable_string spendkey_string = input_secure_line("Secret spend key: ");
+ epee::wipeable_string spendkey_string = input_secure_line("Secret spend key");
if (std::cin.eof())
return false;
if (spendkey_string.empty()) {
@@ -3487,7 +3503,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_keys;
// parse address
- std::string address_string = input_line("Standard address: ");
+ std::string address_string = input_line("Standard address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3507,7 +3523,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse spend secret key
- epee::wipeable_string spendkey_string = input_secure_line("Secret spend key: ");
+ epee::wipeable_string spendkey_string = input_secure_line("Secret spend key");
if (std::cin.eof())
return false;
if (spendkey_string.empty()) {
@@ -3522,7 +3538,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse view secret key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
@@ -3569,7 +3585,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
unsigned int multisig_n;
// parse multisig type
- std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1): ");
+ std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1)");
if (std::cin.eof())
return false;
if (multisig_type_string.empty())
@@ -3595,7 +3611,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
message_writer() << boost::format(tr("Generating master wallet from %u of %u multisig wallet keys")) % multisig_m % multisig_n;
// parse multisig address
- std::string address_string = input_line("Multisig wallet address: ");
+ std::string address_string = input_line("Multisig wallet address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3610,7 +3626,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse secret view key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty())
@@ -3649,7 +3665,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
// get N secret spend keys from user
for(unsigned int i=0; i<multisig_n; ++i)
{
- spendkey_string = input_secure_line(tr((boost::format(tr("Secret spend key (%u of %u):")) % (i+1) % multisig_m).str().c_str()));
+ spendkey_string = input_secure_line(tr((boost::format(tr("Secret spend key (%u of %u)")) % (i+1) % multisig_m).str().c_str()));
if (std::cin.eof())
return false;
if (spendkey_string.empty())
@@ -3726,7 +3742,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
wrt << tr("Assumed you are creating a new account, restore will be done from current estimated blockchain height.") << " ";
wrt << tr("Use --restore-height or --restore-date if you want to restore an already setup account from a specific height.");
}
- std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Is this okay?"), true);
if (std::cin.eof() || !command_line::is_yes(confirm))
CHECK_AND_ASSERT_MES(false, false, tr("account creation aborted"));
@@ -3782,9 +3798,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
std::string heightstr;
if (!connected || version < MAKE_CORE_RPC_VERSION(1, 6))
- heightstr = input_line("Restore from specific blockchain height (optional, default 0): ");
+ heightstr = input_line("Restore from specific blockchain height (optional, default 0)");
else
- heightstr = input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD): ");
+ heightstr = input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD)");
if (std::cin.eof())
return false;
if (heightstr.empty())
@@ -3813,7 +3829,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day);
success_msg_writer() << tr("Restore height is: ") << m_restore_height;
- std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Is this okay?"), true);
if (std::cin.eof())
return false;
if(command_line::is_yes(confirm))
@@ -3836,7 +3852,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (m_restore_height >= estimate_height)
{
success_msg_writer() << tr("Restore height ") << m_restore_height << (" is not yet reached. The current estimated height is ") << estimate_height;
- std::string confirm = input_line(tr("Still apply restore height? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Still apply restore height?"), true);
if (std::cin.eof() || command_line::is_no(confirm))
m_restore_height = 0;
}
@@ -3901,6 +3917,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
m_subaddress_lookahead = command_line::get_arg(vm, arg_subaddress_lookahead);
m_use_english_language_names = command_line::get_arg(vm, arg_use_english_language_names);
+ m_long_payment_id_support = command_line::get_arg(vm, arg_long_payment_id_support);
m_restoring = !m_generate_from_view_key.empty() ||
!m_generate_from_spend_key.empty() ||
!m_generate_from_keys.empty() ||
@@ -3968,7 +3985,7 @@ std::string simple_wallet::get_mnemonic_language()
}
while (language_number < 0)
{
- language_choice = input_line(tr("Enter the number corresponding to the language of your choice: "));
+ language_choice = input_line(tr("Enter the number corresponding to the language of your choice"));
if (std::cin.eof())
return std::string();
try
@@ -4614,7 +4631,7 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
tr("NOTE: this transaction uses an encrypted payment ID: consider using subaddresses instead");
else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
message_writer(console_color_red, false) <<
- tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead");
+ (m_long_payment_id_support ? tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead.") : tr("WARNING: this transaction uses an unencrypted payment ID: these are obsolete. Support will be withdrawn in the future. Use subaddresses instead."));
}
}
if (m_auto_refresh_refreshing)
@@ -5313,6 +5330,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
bool r = true;
if (tools::wallet2::parse_long_payment_id(payment_id_str, payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
std::string extra_nonce;
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
@@ -5423,6 +5442,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
else if (tools::wallet2::parse_payment_id(payment_id_uri, payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
message_writer() << tr("Unencrypted payment IDs are bad for privacy: ask the recipient to use subaddresses instead");
}
@@ -5444,9 +5464,9 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
// prompt is there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5510,23 +5530,23 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
std::vector<std::pair<uint64_t, uint64_t>> nblocks = m_wallet->estimate_backlog({std::make_pair(worst_fee_per_byte, worst_fee_per_byte)});
if (nblocks.size() != 1)
{
- prompt << "Internal error checking for backlog. " << tr("Is this okay anyway? (Y/Yes/N/No): ");
+ prompt << "Internal error checking for backlog. " << tr("Is this okay anyway?");
}
else
{
if (nblocks[0].first > m_wallet->get_confirm_backlog_threshold())
- prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No): ")) % nblocks[0].first).str();
+ prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay?")) % nblocks[0].first).str();
}
}
catch (const std::exception &e)
{
- prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway? (Y/Yes/N/No): ");
+ prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway?");
}
std::string prompt_str = prompt.str();
if (!prompt_str.empty())
{
- std::string accepted = input_line(prompt_str);
+ std::string accepted = input_line(prompt_str, true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5612,9 +5632,9 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
{
prompt << tr("WARNING: this is a non default ring size, which may harm your privacy. Default is recommended.");
}
- prompt << ENDL << tr("Is this okay? (Y/Yes/N/No): ");
+ prompt << ENDL << tr("Is this okay?");
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5752,17 +5772,17 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
std::string prompt_str = tr("Sweeping ") + print_money(total_unmixable);
if (ptx_vector.size() > 1) {
- prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) %
print_money(total_unmixable) %
((unsigned long long)ptx_vector.size()) %
print_money(total_fee)).str();
}
else {
- prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_unmixable) %
print_money(total_fee)).str();
}
- std::string accepted = input_line(prompt_str);
+ std::string accepted = input_line(prompt_str, true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -5805,7 +5825,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
catch (const tools::error::not_enough_unlocked_money& e)
{
fail_msg_writer() << tr("Not enough money in unlocked balance");
- std::string accepted = input_line((boost::format(tr("Discarding %s of unmixable outputs that cannot be spent, which can be undone by \"rescan_spent\". Is this okay? (Y/Yes/N/No): ")) % print_money(e.available())).str());
+ std::string accepted = input_line((boost::format(tr("Discarding %s of unmixable outputs that cannot be spent, which can be undone by \"rescan_spent\". Is this okay?")) % print_money(e.available())).str(), true);
if (std::cin.eof())
return true;
if (command_line::is_yes(accepted))
@@ -5967,6 +5987,8 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
bool r = tools::wallet2::parse_long_payment_id(payment_id_str, payment_id);
if(r)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
std::string extra_nonce;
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
@@ -6011,9 +6033,9 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
}
// prompt is there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6061,17 +6083,17 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
if (m_wallet->print_ring_members() && !print_ring_members(ptx_vector, prompt))
return true;
if (ptx_vector.size() > 1) {
- prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
((unsigned long long)ptx_vector.size()) %
print_money(total_fee);
}
else {
- prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
print_money(total_fee);
}
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6222,6 +6244,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
std::string extra_nonce;
if (tools::wallet2::parse_long_payment_id(local_args.back(), payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
}
else
@@ -6279,9 +6302,9 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
}
// prompt if there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6323,10 +6346,10 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
std::ostringstream prompt;
if (!print_ring_members(ptx_vector, prompt))
return true;
- prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
print_money(total_fee);
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6495,6 +6518,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
if (!payment_id_string.empty())
payment_id_string += ", ";
payment_id_string = std::string("unencrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id);
+ payment_id_string += " (OBSOLETE)";
}
}
}
@@ -6590,8 +6614,8 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
change_string += tr("no change");
uint64_t fee = amount - amount_to_dests;
- std::string prompt_str = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu, %s. %sIs this okay? (Y/Yes/N/No): ")) % (unsigned long)get_num_txes() % print_money(amount) % print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % payment_id_string % extra_message).str();
- return command_line::is_yes(input_line(prompt_str));
+ std::string prompt_str = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu, %s. %sIs this okay?")) % (unsigned long)get_num_txes() % print_money(amount) % print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % payment_id_string % extra_message).str();
+ return command_line::is_yes(input_line(prompt_str, true));
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs)
@@ -7749,7 +7773,7 @@ bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
{
message_writer() << tr("Warning: this will lose any information which can not be recovered from the blockchain.");
message_writer() << tr("This includes destination addresses, tx secret keys, tx notes, etc");
- std::string confirm = input_line(tr("Rescan anyway ? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Rescan anyway?"), true);
if(!std::cin.eof())
{
if (!command_line::is_yes(confirm))
@@ -8223,6 +8247,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
{
if (tools::wallet2::parse_long_payment_id(args[3], payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
description_start += 2;
}
else if (tools::wallet2::parse_short_payment_id(args[3], info.payment_id))
@@ -8266,7 +8291,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
auto& row = address_book[i];
success_msg_writer() << tr("Index: ") << i;
success_msg_writer() << tr("Address: ") << get_account_address_as_str(m_wallet->nettype(), row.m_is_subaddress, row.m_address);
- success_msg_writer() << tr("Payment ID: ") << row.m_payment_id;
+ success_msg_writer() << tr("Payment ID: ") << row.m_payment_id << " (OBSOLETE)";
success_msg_writer() << tr("Description: ") << row.m_description << "\n";
}
}
@@ -8949,6 +8974,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_create_address_file);
command_line::add_arg(desc_params, arg_subaddress_lookahead);
command_line::add_arg(desc_params, arg_use_english_language_names);
+ command_line::add_arg(desc_params, arg_long_payment_id_support);
po::positional_options_description positional_options;
positional_options.add(arg_command.name, -1);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index f364df2ff..c3dc16d96 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -398,6 +398,8 @@ namespace cryptonote
bool m_auto_refresh_refreshing;
std::atomic<bool> m_in_manual_refresh;
uint32_t m_current_subaddress_account;
+
+ bool m_long_payment_id_support;
// MMS
mms::message_store& get_message_store() const { return m_wallet->get_message_store(); };
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 8b2735b01..c6b70ee2e 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1681,7 +1681,25 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_txid = txid;
td.m_key_image = tx_scan_info[o].ki;
td.m_key_image_known = !m_watch_only && !m_multisig;
- td.m_key_image_requested = false;
+ if (!td.m_key_image_known)
+ {
+ // we might have cold signed, and have a mapping to key images
+ std::unordered_map<crypto::public_key, crypto::key_image>::const_iterator i = m_cold_key_images.find(tx_scan_info[o].in_ephemeral.pub);
+ if (i != m_cold_key_images.end())
+ {
+ td.m_key_image = i->second;
+ td.m_key_image_known = true;
+ }
+ }
+ if (m_watch_only)
+ {
+ // for view wallets, that flag means "we want to request it"
+ td.m_key_image_request = true;
+ }
+ else
+ {
+ td.m_key_image_request = false;
+ }
td.m_key_image_partial = m_multisig;
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
@@ -1703,7 +1721,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_rct = false;
}
set_unspent(m_transfers.size()-1);
- if (!m_multisig && !m_watch_only)
+ if (td.m_key_image_known)
m_key_images[td.m_key_image] = m_transfers.size()-1;
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
if (output_tracker_cache)
@@ -5924,6 +5942,61 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
txs.back().additional_tx_keys = additional_tx_keys;
}
+ // add key image mapping for these txes
+ const account_keys &keys = get_account().get_keys();
+ hw::device &hwdev = m_account.get_device();
+ for (size_t n = 0; n < exported_txs.txes.size(); ++n)
+ {
+ const cryptonote::transaction &tx = signed_txes.ptx[n].tx;
+
+ crypto::key_derivation derivation;
+ std::vector<crypto::key_derivation> additional_derivations;
+
+ // compute public keys from out secret keys
+ crypto::public_key tx_pub_key;
+ crypto::secret_key_to_public_key(txs[n].tx_key, tx_pub_key);
+ std::vector<crypto::public_key> additional_tx_pub_keys;
+ for (const crypto::secret_key &skey: txs[n].additional_tx_keys)
+ {
+ additional_tx_pub_keys.resize(additional_tx_pub_keys.size() + 1);
+ crypto::secret_key_to_public_key(skey, additional_tx_pub_keys.back());
+ }
+
+ // compute derivations
+ hwdev.set_mode(hw::device::TRANSACTION_PARSE);
+ if (!hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation))
+ {
+ MWARNING("Failed to generate key derivation from tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
+ static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key");
+ memcpy(&derivation, rct::identity().bytes, sizeof(derivation));
+ }
+ for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
+ {
+ additional_derivations.push_back({});
+ if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
+ {
+ MWARNING("Failed to generate key derivation from additional tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
+ memcpy(&additional_derivations.back(), rct::identity().bytes, sizeof(crypto::key_derivation));
+ }
+ }
+
+ for (size_t i = 0; i < tx.vout.size(); ++i)
+ {
+ if (tx.vout[i].target.type() != typeid(cryptonote::txout_to_key))
+ continue;
+ const cryptonote::txout_to_key &out = boost::get<cryptonote::txout_to_key>(tx.vout[i].target);
+ // if this output is back to this wallet, we can calculate its key image already
+ if (!is_out_to_acc_precomp(m_subaddresses, out.key, derivation, additional_derivations, i, hwdev))
+ continue;
+ crypto::key_image ki;
+ cryptonote::keypair in_ephemeral;
+ if (generate_key_image_helper(keys, m_subaddresses, out.key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev))
+ signed_txes.tx_key_images[out.key] = ki;
+ else
+ MERROR("Failed to calculate key image");
+ }
+ }
+
// add key images
signed_txes.key_images.resize(m_transfers.size());
for (size_t i = 0; i < m_transfers.size(); ++i)
@@ -6086,6 +6159,10 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too
bool r = import_key_images(signed_txs.key_images);
if (!r) return false;
+ // remember key images for this tx, for when we get those txes from the blockchain
+ for (const auto &e: signed_txs.tx_key_images)
+ m_cold_key_images.insert(e);
+
ptx = signed_txs.ptx;
return true;
@@ -8284,7 +8361,7 @@ void wallet2::light_wallet_get_unspent_outs()
td.m_key_image = unspent_key_image;
td.m_key_image_known = !m_watch_only && !m_multisig;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = m_multisig;
td.m_amount = o.amount;
td.m_pk_index = 0;
@@ -10894,7 +10971,7 @@ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>>
size_t offset = 0;
if (!all)
{
- while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_requested)
+ while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_request)
++offset;
}
@@ -11054,7 +11131,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
m_transfers[n + offset].m_key_image = signed_key_images[n].first;
m_key_images[m_transfers[n + offset].m_key_image] = n + offset;
m_transfers[n + offset].m_key_image_known = true;
- m_transfers[n + offset].m_key_image_requested = false;
+ m_transfers[n + offset].m_key_image_request = false;
m_transfers[n + offset].m_key_image_partial = false;
}
PERF_TIMER_STOP(import_key_images_B);
@@ -11273,7 +11350,7 @@ bool wallet2::import_key_images(std::vector<crypto::key_image> key_images)
td.m_key_image = key_images[i];
m_key_images[m_transfers[i].m_key_image] = i;
td.m_key_image_known = true;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = false;
m_pub_keys[m_transfers[i].get_public_key()] = i;
}
@@ -11345,7 +11422,7 @@ std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export
std::vector<tools::wallet2::transfer_details> outs;
size_t offset = 0;
- while (offset < m_transfers.size() && m_transfers[offset].m_key_image_known)
+ while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request))
++offset;
outs.reserve(m_transfers.size() - offset);
@@ -11389,7 +11466,7 @@ size_t wallet2::import_outputs(const std::pair<size_t, std::vector<tools::wallet
const size_t original_size = m_transfers.size();
m_transfers.resize(offset + outputs.second.size());
for (size_t i = 0; i < offset; ++i)
- m_transfers[i].m_key_image_requested = false;
+ m_transfers[i].m_key_image_request = false;
for (size_t i = 0; i < outputs.second.size(); ++i)
{
transfer_details td = outputs.second[i];
@@ -11430,7 +11507,7 @@ process:
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
expand_subaddresses(td.m_subaddr_index);
td.m_key_image_known = true;
- td.m_key_image_requested = true;
+ td.m_key_image_request = true;
td.m_key_image_partial = false;
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i + offset));
@@ -11676,7 +11753,7 @@ void wallet2::update_multisig_rescan_info(const std::vector<std::vector<rct::key
m_key_images.erase(td.m_key_image);
td.m_key_image = get_multisig_composite_key_image(n);
td.m_key_image_known = true;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = false;
td.m_multisig_k = multisig_k[n];
m_key_images[td.m_key_image] = n;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 364e31483..ed92aec19 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -267,7 +267,7 @@ namespace tools
uint64_t m_amount;
bool m_rct;
bool m_key_image_known;
- bool m_key_image_requested;
+ bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested
size_t m_pk_index;
cryptonote::subaddress_index m_subaddr_index;
bool m_key_image_partial;
@@ -292,7 +292,7 @@ namespace tools
FIELD(m_amount)
FIELD(m_rct)
FIELD(m_key_image_known)
- FIELD(m_key_image_requested)
+ FIELD(m_key_image_request)
FIELD(m_pk_index)
FIELD(m_subaddr_index)
FIELD(m_key_image_partial)
@@ -448,6 +448,7 @@ namespace tools
{
std::vector<pending_tx> ptx;
std::vector<crypto::key_image> key_images;
+ std::unordered_map<crypto::public_key, crypto::key_image> tx_key_images;
};
struct multisig_tx_set
@@ -927,6 +928,9 @@ namespace tools
if(ver < 27)
return;
a & m_device_last_key_image_sync;
+ if(ver < 28)
+ return;
+ a & m_cold_key_images;
}
/*!
@@ -1358,6 +1362,7 @@ namespace tools
uint64_t m_upper_transaction_weight_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
const std::vector<std::vector<tools::wallet2::multisig_info>> *m_multisig_rescan_info;
const std::vector<std::vector<rct::key>> *m_multisig_rescan_k;
+ std::unordered_map<crypto::public_key, crypto::key_image> m_cold_key_images;
std::atomic<bool> m_run;
@@ -1452,7 +1457,7 @@ namespace tools
std::unique_ptr<wallet_device_callback> m_device_callback;
};
}
-BOOST_CLASS_VERSION(tools::wallet2, 27)
+BOOST_CLASS_VERSION(tools::wallet2, 28)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
@@ -1464,7 +1469,7 @@ BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 17)
BOOST_CLASS_VERSION(tools::wallet2::reserve_proof_entry, 0)
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
-BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
+BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 1)
BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 3)
BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 3)
BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 0)
@@ -1513,7 +1518,7 @@ namespace boost
}
if (ver < 10)
{
- x.m_key_image_requested = false;
+ x.m_key_image_request = false;
}
}
@@ -1601,7 +1606,7 @@ namespace boost
initialize_transfer_details(a, x, ver);
return;
}
- a & x.m_key_image_requested;
+ a & x.m_key_image_request;
if (ver < 11)
return;
a & x.m_uses;
@@ -1801,6 +1806,9 @@ namespace boost
{
a & x.ptx;
a & x.key_images;
+ if (ver < 1)
+ return;
+ a & x.tx_key_images;
}
template <class Archive>
diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp
index 75cf2fdd4..3d5882d7d 100644
--- a/tests/unit_tests/epee_utils.cpp
+++ b/tests/unit_tests/epee_utils.cpp
@@ -50,6 +50,7 @@
#include "p2p/net_peerlist_boost_serialization.h"
#include "span.h"
#include "string_tools.h"
+#include "storages/parserse_base_utils.h"
namespace
{
@@ -833,3 +834,86 @@ TEST(net_buffer, move)
ASSERT_TRUE(!memcmp(span.data() + 1, std::string(4000, '0').c_str(), 4000));
}
+TEST(parsing, isspace)
+{
+ ASSERT_FALSE(epee::misc_utils::parse::isspace(0));
+ for (int c = 1; c < 256; ++c)
+ {
+ ASSERT_EQ(epee::misc_utils::parse::isspace(c), strchr("\r\n\t\f\v ", c) != NULL);
+ }
+}
+
+TEST(parsing, isdigit)
+{
+ ASSERT_FALSE(epee::misc_utils::parse::isdigit(0));
+ for (int c = 1; c < 256; ++c)
+ {
+ ASSERT_EQ(epee::misc_utils::parse::isdigit(c), strchr("0123456789", c) != NULL);
+ }
+}
+
+TEST(parsing, number)
+{
+ boost::string_ref val;
+ std::string s;
+ std::string::const_iterator i;
+
+ // the parser expects another character to end the number, and accepts things
+ // that aren't numbers, as it's meant as a pre-filter for strto* functions,
+ // so we just check that numbers get accepted, but don't test non numbers
+
+ s = "0 ";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "0");
+
+ s = "000 ";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "000");
+
+ s = "10x";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "10");
+
+ s = "10.09/";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "10.09");
+
+ s = "-1.r";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "-1.");
+
+ s = "-49.;";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "-49.");
+
+ s = "0.78/";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "0.78");
+
+ s = "33E9$";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "33E9");
+
+ s = ".34e2=";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, ".34e2");
+
+ s = "-9.34e-2=";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "-9.34e-2");
+
+ s = "+9.34e+03=";
+ i = s.begin();
+ epee::misc_utils::parse::match_number(i, s.end(), val);
+ ASSERT_EQ(val, "+9.34e+03");
+}
diff --git a/tests/unit_tests/testdb.h b/tests/unit_tests/testdb.h
index b8fef8ed3..8f5cf70e8 100644
--- a/tests/unit_tests/testdb.h
+++ b/tests/unit_tests/testdb.h
@@ -89,7 +89,7 @@ public:
virtual uint64_t get_tx_block_height(const crypto::hash& h) const { return 0; }
virtual uint64_t get_num_outputs(const uint64_t& amount) const { return 1; }
virtual uint64_t get_indexing_base() const { return 0; }
- virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const { return cryptonote::output_data_t(); }
+ virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const { return cryptonote::output_data_t(); }
virtual cryptonote::tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const { return cryptonote::tx_out_index(); }
virtual cryptonote::tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const { return cryptonote::tx_out_index(); }
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<cryptonote::tx_out_index> &indices) const {}