mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
Merge commit '13b1297' into LokiMergeUpstream
This commit is contained in:
commit
d0bab8e6f5
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 && \
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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 == '-')
|
||||
{
|
||||
if(isdigit(*it) || (it == star_end_string && *it == '-') || (val.size() && *it == '.' ) || (is_float_val && (*it == 'e' || *it == 'E' || *it == '-' || *it == '+' )) )
|
||||
{
|
||||
if(!val.size() && *it == '-')
|
||||
is_signed_val = true;
|
||||
if(*it == '.' )
|
||||
is_float_val = true;
|
||||
val.push_back(*it);
|
||||
++chars;
|
||||
++it;
|
||||
}
|
||||
for(;it != buf_end;it++)
|
||||
{
|
||||
const uint8_t flags = lut[(uint8_t)*it];
|
||||
if (flags & 16)
|
||||
{
|
||||
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
|
||||
{
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -1274,7 +1274,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
|
||||
|
|
|
@ -2542,7 +2542,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();
|
||||
|
@ -2569,6 +2569,7 @@ 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));;
|
||||
if (include_commitmemt)
|
||||
ret.commitment = rct::zeroCommit(amount);
|
||||
}
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
|
|
@ -246,7 +246,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;
|
||||
|
|
|
@ -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))
|
||||
|
@ -360,10 +483,6 @@ 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;
|
||||
|
||||
const std::string state_file_path = (boost::filesystem::path(opt_data_dir) / "ancestry-state.bin").string();
|
||||
|
@ -389,8 +508,11 @@ int main(int argc, char* argv[])
|
|||
stop_requested = true;
|
||||
});
|
||||
|
||||
MINFO("Starting from height " << state.height);
|
||||
// forward method
|
||||
const uint64_t db_height = db->height();
|
||||
if (opt_refresh)
|
||||
{
|
||||
MINFO("Starting from height " << state.height);
|
||||
state.block_cache.reserve(db_height);
|
||||
for (uint64_t h = state.height; h < db_height; ++h)
|
||||
{
|
||||
|
@ -451,114 +573,21 @@ int main(int argc, char* argv[])
|
|||
else
|
||||
{
|
||||
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 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)
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -569,10 +598,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;
|
||||
|
@ -596,14 +621,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);
|
||||
|
@ -636,108 +677,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");
|
||||
if (stop_requested)
|
||||
goto done;
|
||||
|
||||
::tx_data_t tx_data2;
|
||||
if (!get_transaction(state, db, txid, tx_data2))
|
||||
return 1;
|
||||
}
|
||||
cryptonote::transaction tx;
|
||||
if (!cryptonote::parse_and_validate_tx_base_from_blob(bd, tx))
|
||||
{
|
||||
LOG_PRINT_L0("Bad tx: " << txid);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -750,6 +723,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);
|
||||
|
|
|
@ -130,6 +130,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,
|
||||
|
@ -158,6 +166,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", ""};
|
||||
|
||||
|
@ -168,13 +177,13 @@ 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>] (<URI> | <address> <amount>) [<payment_id>]");
|
||||
const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id>]");
|
||||
const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] <address> <lockblocks> [<payment_id>]");
|
||||
const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] <address> <lockblocks> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_REGISTER_SERVICE_NODE("register_service_node [index=<N1>[,<N2>,...]] [priority] [auto] <operator cut> <address1> <fraction1> [<address2> <fraction2> [...]] <expiration timestamp> <pubkey> <signature>");
|
||||
const char* USAGE_STAKE("stake [index=<N1>[,<N2>,...]] [priority] <service node pubkey> <address> <amount>");
|
||||
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [outputs=<N>] <address> [<payment_id>]");
|
||||
const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] <address> [<payment_id>]");
|
||||
const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [outputs=<N>] <key_image> <address> [<payment_id>]");
|
||||
const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] <address> [<payment_id (obsolete)>]");
|
||||
const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [outputs=<N>] <key_image> <address> [<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"
|
||||
|
@ -250,12 +259,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
|
||||
|
@ -267,12 +279,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");
|
||||
|
@ -456,10 +468,10 @@ namespace
|
|||
<< ", " << dnssec_str << std::endl
|
||||
<< sw::tr(" Loki 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 {};
|
||||
|
@ -627,7 +639,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;
|
||||
}
|
||||
|
@ -891,6 +903,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)
|
||||
{
|
||||
|
@ -2207,6 +2221,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)
|
||||
{
|
||||
|
@ -2775,7 +2791,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),
|
||||
|
@ -2840,7 +2856,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."));
|
||||
|
@ -3146,9 +3162,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())
|
||||
{
|
||||
|
@ -3195,7 +3211,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()");
|
||||
|
@ -3404,7 +3420,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()) {
|
||||
|
@ -3424,7 +3440,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()) {
|
||||
|
@ -3459,7 +3475,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()) {
|
||||
|
@ -3479,7 +3495,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()) {
|
||||
|
@ -3499,7 +3515,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()) {
|
||||
|
@ -3514,7 +3530,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()) {
|
||||
|
@ -3561,7 +3577,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())
|
||||
|
@ -3587,7 +3603,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()) {
|
||||
|
@ -3602,7 +3618,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())
|
||||
|
@ -3641,7 +3657,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())
|
||||
|
@ -3714,11 +3730,11 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
|
|||
if(m_wallet->get_refresh_from_block_height() == 0) {
|
||||
{
|
||||
tools::scoped_message_writer wrt = tools::msg_writer();
|
||||
wrt << tr("No restore height is specified.");
|
||||
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");
|
||||
wrt << tr("No restore height is specified.") << " ";
|
||||
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"));
|
||||
|
||||
|
@ -3774,9 +3790,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())
|
||||
|
@ -3805,7 +3821,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))
|
||||
|
@ -3828,7 +3844,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;
|
||||
}
|
||||
|
@ -3893,6 +3909,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() ||
|
||||
|
@ -3960,7 +3977,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
|
||||
|
@ -4606,7 +4623,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)
|
||||
|
@ -5295,6 +5312,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);
|
||||
|
@ -5395,6 +5414,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");
|
||||
}
|
||||
|
@ -5416,9 +5436,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))
|
||||
|
@ -5482,23 +5502,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))
|
||||
|
@ -5584,9 +5604,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))
|
||||
|
@ -5872,14 +5892,14 @@ bool simple_wallet::register_service_node_main(
|
|||
return true;
|
||||
}
|
||||
if (ptx_vector.size() > 1) {
|
||||
prompt << boost::format(tr("Staking %s for %u blocks in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
|
||||
prompt << boost::format(tr("Staking %s for %u blocks in %llu transactions for a total fee of %s. Is this okay?")) %
|
||||
print_money(total_sent) %
|
||||
locked_blocks %
|
||||
((unsigned long long)ptx_vector.size()) %
|
||||
print_money(total_fee);
|
||||
}
|
||||
else {
|
||||
prompt << boost::format(tr("Staking %s for %u blocks a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
|
||||
prompt << boost::format(tr("Staking %s for %u blocks a total fee of %s. Is this okay?: ")) %
|
||||
print_money(total_sent) %
|
||||
locked_blocks %
|
||||
print_money(total_fee);
|
||||
|
@ -5890,7 +5910,7 @@ bool simple_wallet::register_service_node_main(
|
|||
}
|
||||
else
|
||||
{
|
||||
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))
|
||||
|
@ -5935,7 +5955,7 @@ bool simple_wallet::register_service_node_main(
|
|||
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))
|
||||
|
@ -6166,7 +6186,7 @@ bool simple_wallet::stake_main(
|
|||
return true;
|
||||
}
|
||||
fail_msg_writer() << tr("Wallet not synced. Best guess for the height is ") << bc_height;
|
||||
std::string accepted = input_line("Is this correct [y/yes/n/no]? ");
|
||||
std::string accepted = input_line("Is this correct?", true);
|
||||
if (std::cin.eof())
|
||||
return true;
|
||||
if (!command_line::is_yes(accepted))
|
||||
|
@ -6340,14 +6360,14 @@ bool simple_wallet::stake_main(
|
|||
return true;
|
||||
}
|
||||
if (ptx_vector.size() > 1) {
|
||||
prompt << boost::format(tr("Staking %s for %u blocks in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
|
||||
prompt << boost::format(tr("Staking %s for %u blocks in %llu transactions for a total fee of %s. Is this okay?")) %
|
||||
print_money(total_sent) %
|
||||
locked_blocks %
|
||||
((unsigned long long)ptx_vector.size()) %
|
||||
print_money(total_fee);
|
||||
}
|
||||
else {
|
||||
prompt << boost::format(tr("Staking %s for %u blocks a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
|
||||
prompt << boost::format(tr("Staking %s for %u blocks a total fee of %s. Is this okay?")) %
|
||||
print_money(total_sent) %
|
||||
locked_blocks %
|
||||
print_money(total_fee);
|
||||
|
@ -6358,7 +6378,7 @@ bool simple_wallet::stake_main(
|
|||
}
|
||||
else
|
||||
{
|
||||
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))
|
||||
|
@ -6647,17 +6667,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))
|
||||
|
@ -6816,6 +6836,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);
|
||||
|
@ -6860,9 +6882,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))
|
||||
|
@ -6910,17 +6932,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))
|
||||
|
@ -7039,6 +7061,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
|
||||
|
@ -7096,9 +7119,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))
|
||||
|
@ -7140,10 +7163,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))
|
||||
|
@ -7251,6 +7274,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)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7346,8 +7370,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)
|
||||
|
@ -8582,7 +8606,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))
|
||||
|
@ -9056,6 +9080,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))
|
||||
|
@ -9099,7 +9124,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";
|
||||
}
|
||||
}
|
||||
|
@ -9801,6 +9826,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);
|
||||
|
|
|
@ -411,6 +411,8 @@ namespace cryptonote
|
|||
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(); };
|
||||
mms::multisig_wallet_state get_multisig_wallet_state() const { return m_wallet->get_multisig_wallet_state(); };
|
||||
|
|
|
@ -1676,7 +1676,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;
|
||||
|
@ -1698,7 +1716,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)
|
||||
|
@ -5956,6 +5974,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)
|
||||
|
@ -6118,6 +6191,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;
|
||||
|
@ -8412,7 +8489,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;
|
||||
|
@ -11025,7 +11102,7 @@ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>>
|
|||
|
||||
if (requested_only)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -11185,7 +11262,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);
|
||||
|
@ -11404,7 +11481,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;
|
||||
}
|
||||
|
@ -11476,7 +11553,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);
|
||||
|
@ -11520,7 +11597,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];
|
||||
|
@ -11561,7 +11638,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));
|
||||
|
@ -11807,7 +11884,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;
|
||||
|
|
|
@ -306,7 +306,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;
|
||||
|
@ -331,7 +331,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)
|
||||
|
@ -492,6 +492,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
|
||||
|
@ -973,6 +974,9 @@ namespace tools
|
|||
if(ver < 27)
|
||||
return;
|
||||
a & m_device_last_key_image_sync;
|
||||
if(ver < 28)
|
||||
return;
|
||||
a & m_cold_key_images;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -1408,6 +1412,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;
|
||||
|
||||
|
@ -1503,7 +1508,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)
|
||||
|
@ -1515,7 +1520,7 @@ BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 7)
|
|||
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, 4)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 3)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 0)
|
||||
|
@ -1564,7 +1569,7 @@ namespace boost
|
|||
}
|
||||
if (ver < 10)
|
||||
{
|
||||
x.m_key_image_requested = false;
|
||||
x.m_key_image_request = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1652,7 +1657,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;
|
||||
|
@ -1856,6 +1861,9 @@ namespace boost
|
|||
{
|
||||
a & x.ptx;
|
||||
a & x.key_images;
|
||||
if (ver < 1)
|
||||
return;
|
||||
a & x.tx_key_images;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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 {}
|
||||
|
|
Loading…
Reference in a new issue