mirror of
https://git.wownero.com/wownero/wownero.git
synced 2025-01-06 20:48:53 +00:00
commit
111e25f10d
@ -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 == '+' )) )
|
||||
is_signed_val = true;
|
||||
++chars;
|
||||
++it;
|
||||
}
|
||||
for(;it != buf_end;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
|
||||
{
|
||||
|
@ -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"))
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
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())
|
||||
{
|
||||
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();
|
||||
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");
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
@ -229,12 +229,15 @@ namespace
|
||||
const char* USAGE_HELP("help");
|
||||
const char* USAGE_HELP_ADVANCED("help_advanced [<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
|
||||
@ -424,10 +427,10 @@ namespace
|
||||
<< ", " << dnssec_str << std::endl
|
||||
<< sw::tr(" Wownero 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 {};
|
||||
@ -595,7 +598,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;
|
||||
}
|
||||
@ -3153,9 +3156,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())
|
||||
{
|
||||
@ -3202,7 +3205,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()");
|
||||
@ -3411,7 +3414,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()) {
|
||||
@ -3431,7 +3434,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()) {
|
||||
@ -3466,7 +3469,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()) {
|
||||
@ -3486,7 +3489,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()) {
|
||||
@ -3506,7 +3509,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()) {
|
||||
@ -3521,7 +3524,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()) {
|
||||
@ -3568,7 +3571,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())
|
||||
@ -3594,7 +3597,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()) {
|
||||
@ -3609,7 +3612,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())
|
||||
@ -3648,7 +3651,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())
|
||||
@ -3721,11 +3724,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"));
|
||||
|
||||
@ -3781,9 +3784,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())
|
||||
@ -3812,7 +3815,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))
|
||||
@ -3835,7 +3838,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;
|
||||
}
|
||||
@ -3967,7 +3970,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
|
||||
@ -5394,7 +5397,7 @@ 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)
|
||||
{
|
||||
std::string accepted = input_line(tr("There is no easy way for exchanges and large merchants to identify that this transaction came from you. Request a subaddress in these cases. Continue anyway? (Y/Yes/N/No): "));
|
||||
std::string accepted = input_line(tr("There is no easy way for exchanges and large merchants to identify that this transaction came from you. Request a subaddress in these cases. Continue anyway?"), true);
|
||||
if (std::cin.eof())
|
||||
return false;
|
||||
if (!command_line::is_yes(accepted))
|
||||
@ -5458,23 +5461,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))
|
||||
@ -5560,9 +5563,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))
|
||||
@ -5700,17 +5703,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))
|
||||
@ -5753,7 +5756,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))
|
||||
@ -5961,7 +5964,7 @@ 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)
|
||||
{
|
||||
std::string accepted = input_line(tr("There is no easy way for exchanges and large merchants to identify that this transaction came from you. Request a subaddress in these cases. Continue anyway? (Y/Yes/N/No): "));
|
||||
std::string accepted = input_line(tr("There is no easy way for exchanges and large merchants to identify that this transaction came from you. Request a subaddress in these cases. Continue anyway?"), true);
|
||||
if (std::cin.eof())
|
||||
return true;
|
||||
if (!command_line::is_yes(accepted))
|
||||
@ -6009,17 +6012,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))
|
||||
@ -6229,7 +6232,7 @@ 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)
|
||||
{
|
||||
std::string accepted = input_line(tr("There is no easy way for exchanges and large merchants to identify that this transaction came from you. Request a subaddress in these cases. Continue anyway? (Y/Yes/N/No): "));
|
||||
std::string accepted = input_line(tr("There is no easy way for exchanges and large merchants to identify that this transaction came from you. Request a subaddress in these cases. Continue anyway?"), true);
|
||||
if (std::cin.eof())
|
||||
return true;
|
||||
if (!command_line::is_yes(accepted))
|
||||
@ -6271,10 +6274,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))
|
||||
@ -6552,8 +6555,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)
|
||||
@ -7711,7 +7714,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))
|
||||
|
@ -1683,7 +1683,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;
|
||||
@ -1705,7 +1723,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)
|
||||
@ -5927,6 +5945,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)
|
||||
@ -6089,6 +6162,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;
|
||||
@ -8293,7 +8370,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;
|
||||
@ -10897,7 +10974,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;
|
||||
}
|
||||
|
||||
@ -11057,7 +11134,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);
|
||||
@ -11276,7 +11353,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;
|
||||
}
|
||||
@ -11348,7 +11425,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);
|
||||
@ -11392,7 +11469,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];
|
||||
@ -11433,7 +11510,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));
|
||||
@ -11679,7 +11756,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;
|
||||
|
@ -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>
|
||||
|
@ -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 New Issue
Block a user