Merge pull request #153 from wowario/upstream

Upstream
release-v0.5.0
jw 6 years ago committed by GitHub
commit d85d908ddc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -23,9 +23,9 @@ env:
- DOCKER_PACKAGES="build-essential libtool cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache" - DOCKER_PACKAGES="build-essential libtool cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache"
matrix: matrix:
# ARM v7 # ARM v7
- HOST=arm-linux-gnueabihf PACKAGES="gperf g++-arm-linux-gnueabihf" - HOST=arm-linux-gnueabihf PACKAGES="python3 gperf g++-arm-linux-gnueabihf"
# ARM v8 # ARM v8
- HOST=aarch64-linux-gnu PACKAGES="gperf g++-aarch64-linux-gnu" - HOST=aarch64-linux-gnu PACKAGES="python3 gperf g++-aarch64-linux-gnu"
# i686 Win # i686 Win
- HOST=i686-w64-mingw32 PACKAGES="python3 nsis g++-mingw-w64-i686" - HOST=i686-w64-mingw32 PACKAGES="python3 nsis g++-mingw-w64-i686"
# i686 Linux # i686 Linux
@ -33,7 +33,7 @@ env:
# Win64 # Win64
- HOST=x86_64-w64-mingw32 PACKAGES="cmake python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 bc" RUN_TESTS=true - HOST=x86_64-w64-mingw32 PACKAGES="cmake python3 nsis g++-mingw-w64-x86-64 wine-binfmt wine64 bc" RUN_TESTS=true
# x86_64 Linux # x86_64 Linux
- HOST=x86_64-unknown-linux-gnu PACKAGES="gperf cmake python3-zmq protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" RUN_TESTS=true - HOST=x86_64-unknown-linux-gnu PACKAGES="gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev" RUN_TESTS=true
# Cross-Mac # Cross-Mac
- HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" OSX_SDK=10.11 - HOST=x86_64-apple-darwin11 PACKAGES="cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git" OSX_SDK=10.11
@ -52,6 +52,7 @@ before_script:
- if [ -n "$OSX_SDK" -a ! -f contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a ! -f contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then curl --location --fail $SDK_URL/MacOSX${OSX_SDK}.sdk.tar.gz -o contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- if [ -n "$OSX_SDK" -a -f contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C contrib/depends/SDKs -xf contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi - if [ -n "$OSX_SDK" -a -f contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz ]; then tar -C contrib/depends/SDKs -xf contrib/depends/sdk-sources/MacOSX${OSX_SDK}.sdk.tar.gz; fi
- if [[ $HOST = *-mingw32 ]]; then $DOCKER_EXEC bash -c "update-alternatives --set $HOST-g++ \$(which $HOST-g++-posix)"; fi - if [[ $HOST = *-mingw32 ]]; then $DOCKER_EXEC bash -c "update-alternatives --set $HOST-g++ \$(which $HOST-g++-posix)"; fi
- if [[ $HOST = *-mingw32 ]]; then $DOCKER_EXEC bash -c "update-alternatives --set $HOST-gcc \$(which $HOST-gcc-posix)"; fi
- if [ -z "$NO_DEPENDS" ]; then $DOCKER_EXEC bash -c "CONFIG_SHELL= make $MAKEJOBS -C contrib/depends HOST=$HOST $DEP_OPTS"; fi - if [ -z "$NO_DEPENDS" ]; then $DOCKER_EXEC bash -c "CONFIG_SHELL= make $MAKEJOBS -C contrib/depends HOST=$HOST $DEP_OPTS"; fi
script: script:
- git submodule init && git submodule update - git submodule init && git submodule update

@ -601,9 +601,6 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_FLAG}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_FLAG}")
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-unused-variable -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized") set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-unused-variable -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized")
if(NOT MINGW)
set(WARNINGS_AS_ERRORS_FLAG "-Werror")
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "Clang") if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
if(ARM) if(ARM)
set(WARNINGS "${WARNINGS} -Wno-error=inline-asm") set(WARNINGS "${WARNINGS} -Wno-error=inline-asm")
@ -698,6 +695,13 @@ else()
set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap") set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap")
endif() endif()
if(BACKCOMPAT)
add_definitions(-DFDELT_TYPE=long\ int)
add_linker_flag_if_supported(-Wl,--wrap=__divmoddi4 LD_BACKCOMPAT_FLAGS)
add_linker_flag_if_supported(-Wl,--wrap=glob LD_BACKCOMPAT_FLAGS)
message(STATUS "Using Lib C back compat flags: ${LD_BACKCOMPAT_FLAGS}")
endif()
# some windows linker bits # some windows linker bits
if (WIN32) if (WIN32)
add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS) add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS)
@ -710,7 +714,7 @@ else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${COVERAGE_FLAGS} ${PIC_FLAG} ${C_SECURITY_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${COVERAGE_FLAGS} ${PIC_FLAG} ${C_SECURITY_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${COVERAGE_FLAGS} ${PIC_FLAG} ${CXX_SECURITY_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${COVERAGE_FLAGS} ${PIC_FLAG} ${CXX_SECURITY_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS} ${LD_BACKCOMPAT_FLAGS}")
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that # With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
# is fixed in the code (Issue #847), force compiler to be conservative. # is fixed in the code (Issue #847), force compiler to be conservative.

@ -19,7 +19,8 @@ posted to #monero-dev on irc.freenode.net).
Patches should be self contained. A good rule of thumb is to have Patches should be self contained. A good rule of thumb is to have
one patch per separate issue, feature, or logical change. Also, no one patch per separate issue, feature, or logical change. Also, no
other changes, such as random whitespace changes or reindentation. other changes, such as random whitespace changes, reindentation,
or fixing typoes, spelling, or wording, unless user visible.
Following the code style of the particular chunk of code you're Following the code style of the particular chunk of code you're
modifying is encouraged. Proper squashing should be done (eg, if modifying is encouraged. Proper squashing should be done (eg, if
you're making a buggy patch, then a later patch to fix the bug, you're making a buggy patch, then a later patch to fix the bug,

@ -20,7 +20,8 @@ RUN set -ex && \
automake \ automake \
bzip2 \ bzip2 \
xsltproc \ xsltproc \
gperf gperf \
unzip
WORKDIR /usr/local WORKDIR /usr/local
@ -147,6 +148,20 @@ RUN set -ex \
&& make \ && make \
&& make install && make install
# Protobuf
ARG PROTOBUF_VERSION=v3.6.1
ARG PROTOBUF_HASH=48cb18e5c419ddd23d9badcfe4e9df7bde1979b2
RUN set -ex \
&& git clone https://github.com/protocolbuffers/protobuf -b ${PROTOBUF_VERSION} \
&& cd protobuf \
&& test `git rev-parse HEAD` = ${PROTOBUF_HASH} || exit 1 \
&& git submodule update --init --recursive \
&& ./autogen.sh \
&& CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./configure --enable-static --disable-shared \
&& make \
&& make install \
&& ldconfig
WORKDIR /src WORKDIR /src
COPY . . COPY . .

@ -2,13 +2,55 @@ OPTION(USE_DEVICE_TREZOR "Trezor support compilation" OFF)
OPTION(USE_DEVICE_TREZOR_LIBUSB "Trezor LibUSB compilation" OFF) OPTION(USE_DEVICE_TREZOR_LIBUSB "Trezor LibUSB compilation" OFF)
OPTION(USE_DEVICE_TREZOR_UDP_RELEASE "Trezor UdpTransport in release mode" OFF) OPTION(USE_DEVICE_TREZOR_UDP_RELEASE "Trezor UdpTransport in release mode" OFF)
# Helper function to fix cmake < 3.6.0 FindProtobuf variables
function(_trezor_protobuf_fix_vars)
if(${CMAKE_VERSION} VERSION_LESS "3.6.0")
foreach(UPPER
PROTOBUF_SRC_ROOT_FOLDER
PROTOBUF_IMPORT_DIRS
PROTOBUF_DEBUG
PROTOBUF_LIBRARY
PROTOBUF_PROTOC_LIBRARY
PROTOBUF_INCLUDE_DIR
PROTOBUF_PROTOC_EXECUTABLE
PROTOBUF_LIBRARY_DEBUG
PROTOBUF_PROTOC_LIBRARY_DEBUG
PROTOBUF_LITE_LIBRARY
PROTOBUF_LITE_LIBRARY_DEBUG
)
if (DEFINED ${UPPER})
string(REPLACE "PROTOBUF_" "Protobuf_" Camel ${UPPER})
if (NOT DEFINED ${Camel})
set(${Camel} ${${UPPER}} PARENT_SCOPE)
endif()
endif()
endforeach()
endif()
endfunction()
# Use Trezor master switch # Use Trezor master switch
if (USE_DEVICE_TREZOR) if (USE_DEVICE_TREZOR)
# Protobuf is required to build protobuf messages for Trezor # Protobuf is required to build protobuf messages for Trezor
include(FindProtobuf OPTIONAL) include(FindProtobuf OPTIONAL)
find_package(Protobuf) find_package(Protobuf)
if(NOT Protobuf_FOUND) _trezor_protobuf_fix_vars()
# Protobuf handling the cache variables set in docker.
if(NOT Protobuf_FOUND AND NOT Protobuf_LIBRARY AND NOT Protobuf_PROTOC_EXECUTABLE AND NOT Protobuf_INCLUDE_DIR)
message(STATUS "Could not find Protobuf") message(STATUS "Could not find Protobuf")
elseif(NOT Protobuf_LIBRARY OR NOT EXISTS "${Protobuf_LIBRARY}")
message(STATUS "Protobuf library not found: ${Protobuf_LIBRARY}")
unset(Protobuf_FOUND)
elseif(NOT Protobuf_PROTOC_EXECUTABLE OR NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
message(STATUS "Protobuf executable not found: ${Protobuf_PROTOC_EXECUTABLE}")
unset(Protobuf_FOUND)
elseif(NOT Protobuf_INCLUDE_DIR OR NOT EXISTS "${Protobuf_INCLUDE_DIR}")
message(STATUS "Protobuf include dir not found: ${Protobuf_INCLUDE_DIR}")
unset(Protobuf_FOUND)
else()
message(STATUS "Protobuf lib: ${Protobuf_LIBRARY}, inc: ${Protobuf_INCLUDE_DIR}, protoc: ${Protobuf_PROTOC_EXECUTABLE}")
set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIR})
set(Protobuf_FOUND 1) # override found if all rquired info was provided by variables
endif() endif()
else() else()
@ -37,9 +79,32 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR)
endif() endif()
endif() endif()
# Try to build protobuf messages # Protobuf compilation test
if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON) if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
set(ENV{PROTOBUF_INCLUDE_DIRS} "${Protobuf_INCLUDE_DIRS}") execute_process(COMMAND ${Protobuf_PROTOC_EXECUTABLE} -I "${CMAKE_SOURCE_DIR}/cmake" -I "${Protobuf_INCLUDE_DIR}" "${CMAKE_SOURCE_DIR}/cmake/test-protobuf.proto" --cpp_out ${CMAKE_BINARY_DIR} RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
if(RET)
message(STATUS "Protobuf test generation failed: ${OUT} ${ERR}")
endif()
try_compile(Protobuf_COMPILE_TEST_PASSED
"${CMAKE_BINARY_DIR}"
SOURCES
"${CMAKE_BINARY_DIR}/test-protobuf.pb.cc"
"${CMAKE_SOURCE_DIR}/cmake/test-protobuf.cpp"
CMAKE_FLAGS
"-DINCLUDE_DIRECTORIES=${Protobuf_INCLUDE_DIR};${CMAKE_BINARY_DIR}"
"-DCMAKE_CXX_STANDARD=11"
LINK_LIBRARIES ${Protobuf_LIBRARY}
OUTPUT_VARIABLE OUTPUT
)
if(NOT Protobuf_COMPILE_TEST_PASSED)
message(STATUS "Protobuf Compilation test failed: ${OUTPUT}.")
endif()
endif()
# Try to build protobuf messages
if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON AND Protobuf_COMPILE_TEST_PASSED)
set(ENV{PROTOBUF_INCLUDE_DIRS} "${Protobuf_INCLUDE_DIR}")
set(ENV{PROTOBUF_PROTOC_EXECUTABLE} "${Protobuf_PROTOC_EXECUTABLE}") set(ENV{PROTOBUF_PROTOC_EXECUTABLE} "${Protobuf_PROTOC_EXECUTABLE}")
execute_process(COMMAND ${TREZOR_PYTHON} tools/build_protob.py WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../src/device_trezor/trezor RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR) execute_process(COMMAND ${TREZOR_PYTHON} tools/build_protob.py WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/../src/device_trezor/trezor RESULT_VARIABLE RET OUTPUT_VARIABLE OUT ERROR_VARIABLE ERR)
if(RET) if(RET)
@ -47,9 +112,10 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
"OUT: ${OUT}, ERR: ${ERR}." "OUT: ${OUT}, ERR: ${ERR}."
"Please read src/device_trezor/trezor/tools/README.md") "Please read src/device_trezor/trezor/tools/README.md")
else() else()
message(STATUS "Trezor protobuf messages regenerated ${OUT}") message(STATUS "Trezor protobuf messages regenerated out: \"${OUT}.\"")
set(DEVICE_TREZOR_READY 1) set(DEVICE_TREZOR_READY 1)
add_definitions(-DDEVICE_TREZOR_READY=1) add_definitions(-DDEVICE_TREZOR_READY=1)
add_definitions(-DPROTOBUF_INLINE_NOT_IN_HEADERS=0)
if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions(-DTREZOR_DEBUG=1) add_definitions(-DTREZOR_DEBUG=1)
@ -75,5 +141,26 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON)
include_directories(${LibUSB_INCLUDE_DIRS}) include_directories(${LibUSB_INCLUDE_DIRS})
endif() endif()
endif() endif()
set(TREZOR_LIBUSB_LIBRARIES "")
if(LibUSB_COMPILE_TEST_PASSED)
list(APPEND TREZOR_LIBUSB_LIBRARIES ${LibUSB_LIBRARIES})
message(STATUS "Trezor compatible LibUSB found at: ${LibUSB_INCLUDE_DIRS}")
endif()
if (BUILD_GUI_DEPS)
set(TREZOR_DEP_LIBS "")
set(TREZOR_DEP_LINKER "")
if (Protobuf_LIBRARY)
list(APPEND TREZOR_DEP_LIBS ${Protobuf_LIBRARY})
string(APPEND TREZOR_DEP_LINKER " -lprotobuf")
endif()
if (TREZOR_LIBUSB_LIBRARIES)
list(APPEND TREZOR_DEP_LIBS ${TREZOR_LIBUSB_LIBRARIES})
string(APPEND TREZOR_DEP_LINKER " -lusb-1.0")
endif()
endif()
endif() endif()
endif() endif()

@ -0,0 +1,43 @@
// Copyright (c) 2014-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <iostream>
#include <google/protobuf/message.h>
#include <google/protobuf/unknown_field_set.h>
#include "test-protobuf.pb.h"
int main(int argc, char *argv[]) {
google::protobuf::UnknownFieldSet ufs;
ufs.ClearAndFreeMemory();
Success sc;
sc.set_message("test");
sc.SerializeToOstream(&std::cerr);
return 0;
}

@ -0,0 +1,7 @@
syntax = "proto2";
import "google/protobuf/descriptor.proto";
message Success {
optional string message = 1;
}

@ -26,10 +26,5 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# warnings are cleared only for GCC on Linux
if (NOT (MINGW OR APPLE OR FREEBSD OR OPENBSD OR DRAGONFLY))
add_compile_options("${WARNINGS_AS_ERRORS_FLAG}") # applies only to targets that follow
endif()
add_subdirectory(epee) add_subdirectory(epee)

@ -53,6 +53,16 @@ Download it from apple, or search for it on github. Create a new directoty calle
directory and place the entire MacOSX10.11.sdk folder in it. The depends build will then pick it up automatically directory and place the entire MacOSX10.11.sdk folder in it. The depends build will then pick it up automatically
(without requiring SDK_PATH). (without requiring SDK_PATH).
#Mingw builds
Building for 32/64bit mingw requires switching alternatives to a posix mode
```bash
update-alternatives --set x86_64-w64-mingw32-g++ x86_64-w64-mingw32-g++-posix
update-alternatives --set x86_64-w64-mingw32-gcc x86_64-w64-mingw32-gcc-posix
```
### Other documentation ### Other documentation
- [description.md](description.md): General description of the depends system - [description.md](description.md): General description of the depends system

@ -11,13 +11,21 @@ endef
define $(package)_set_vars define $(package)_set_vars
$(package)_config_opts=--disable-shared $(package)_config_opts=--disable-shared
$(package)_config_opts_linux=--with-pic --disable-udev $(package)_config_opts_linux=--with-pic --disable-udev
$(package)_config_opts_mingw32=--disable-udev
$(package)_config_opts_darwin=--disable-udev
endef endef
define $(package)_config_cmds ifneq ($(host_os),darwin)
cp -f $(BASEDIR)/config.guess config.guess &&\ define $(package)_config_cmds
cp -f $(BASEDIR)/config.sub config.sub &&\ cp -f $(BASEDIR)/config.guess config.guess &&\
$($(package)_autoconf) cp -f $(BASEDIR)/config.sub config.sub &&\
endef $($(package)_autoconf)
endef
else
define $(package)_config_cmds
$($(package)_autoconf)
endef
endif
define $(package)_build_cmd define $(package)_build_cmd
$(MAKE) $(MAKE)
@ -27,5 +35,5 @@ define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install $(MAKE) DESTDIR=$($(package)_staging_dir) install
endef endef
define $(package)_postprocess_cmds cp -f lib/libusb-1.0.a lib/libusb.a define $(package)_postprocess_cmds cp -f lib/libusb-1.0.a lib/libusb.a
endef endef

@ -0,0 +1,28 @@
package=protobuf3
$(package)_version=3.6.1
$(package)_download_path=https://github.com/protocolbuffers/protobuf/releases/download/v$($(package)_version)/
$(package)_file_name=protobuf-cpp-$($(package)_version).tar.gz
$(package)_sha256_hash=b3732e471a9bb7950f090fd0457ebd2536a9ba0891b7f3785919c654fe2a2529
$(package)_cxxflags=-std=c++11
define $(package)_set_vars
$(package)_config_opts=--disable-shared --prefix=$(build_prefix)
$(package)_config_opts_linux=--with-pic
endef
define $(package)_config_cmds
$($(package)_autoconf)
endef
define $(package)_build_cmds
$(MAKE) -C src libprotobuf.la all
endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) -C src install install-libLTLIBRARIES install-nobase_includeHEADERS &&\
$(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA
endef
define $(package)_postprocess_cmds
rm lib/libprotoc.a
endef

@ -1,10 +1,10 @@
packages:=boost openssl libevent zeromq cppzmq zlib expat ldns cppzmq readline libiconv qt hidapi packages:=boost openssl libevent zeromq cppzmq zlib expat ldns cppzmq readline libiconv qt hidapi protobuf libusb
native_packages := native_ccache native_packages := native_ccache native_protobuf
darwin_native_packages = native_biplist native_ds_store native_mac_alias darwin_native_packages = native_biplist native_ds_store native_mac_alias
darwin_packages = sodium-darwin darwin_packages = sodium-darwin
linux_packages = eudev libusb linux_packages = eudev
ifeq ($(host_os),linux) ifeq ($(host_os),linux)
packages += unwind packages += unwind

@ -21,6 +21,12 @@ SET(LIBUNWIND_LIBRARY_DIRS @prefix@/lib)
SET(LIBUSB-1.0_LIBRARY @prefix@/lib/libusb-1.0.a) SET(LIBUSB-1.0_LIBRARY @prefix@/lib/libusb-1.0.a)
SET(LIBUDEV_LIBRARY @prefix@/lib/libudev.a) SET(LIBUDEV_LIBRARY @prefix@/lib/libudev.a)
SET(Protobuf_FOUND 1)
SET(Protobuf_PROTOC_EXECUTABLE @prefix@/native/bin/protoc CACHE FILEPATH "Path to the native protoc")
SET(Protobuf_INCLUDE_DIR @prefix@/include CACHE PATH "Protobuf include dir")
SET(Protobuf_INCLUDE_DIRS @prefix@/include CACHE PATH "Protobuf include dir")
SET(Protobuf_LIBRARY @prefix@/lib/libprotobuf.a CACHE FILEPATH "Protobuf library")
SET(ZMQ_INCLUDE_PATH @prefix@/include) SET(ZMQ_INCLUDE_PATH @prefix@/include)
SET(ZMQ_LIB @prefix@/lib/libzmq.a) SET(ZMQ_LIB @prefix@/lib/libzmq.a)

@ -230,35 +230,56 @@ namespace math_helper
} }
} }
template<int default_interval, bool start_immediate = true> template<uint64_t scale, int default_interval, bool start_immediate = true>
class once_a_time_seconds class once_a_time
{ {
uint64_t get_time() const
{
#ifdef _WIN32
FILETIME fileTime;
GetSystemTimeAsFileTime(&fileTime);
unsigned __int64 present = 0;
present |= fileTime.dwHighDateTime;
present = present << 32;
present |= fileTime.dwLowDateTime;
present /= 10; // mic-sec
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec * 1000000 + tv.tv_usec;
#endif
}
public: public:
once_a_time_seconds():m_interval(default_interval) once_a_time():m_interval(default_interval * scale)
{ {
m_last_worked_time = 0; m_last_worked_time = 0;
if(!start_immediate) if(!start_immediate)
time(&m_last_worked_time); m_last_worked_time = get_time();
} }
template<class functor_t> template<class functor_t>
bool do_call(functor_t functr) bool do_call(functor_t functr)
{ {
time_t current_time = 0; uint64_t current_time = get_time();
time(&current_time);
if(current_time - m_last_worked_time > m_interval) if(current_time - m_last_worked_time > m_interval)
{ {
bool res = functr(); bool res = functr();
time(&m_last_worked_time); m_last_worked_time = get_time();
return res; return res;
} }
return true; return true;
} }
private: private:
time_t m_last_worked_time; uint64_t m_last_worked_time;
time_t m_interval; uint64_t m_interval;
}; };
template<int default_interval, bool start_immediate = true>
class once_a_time_seconds: public once_a_time<1000000, default_interval, start_immediate> {};
template<int default_interval, bool start_immediate = true>
class once_a_time_milliseconds: public once_a_time<1000, default_interval, start_immediate> {};
} }
} }

@ -38,14 +38,21 @@
#define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes #define MAX_LOG_FILE_SIZE 104850000 // 100 MB - 7600 bytes
#define MAX_LOG_FILES 50 #define MAX_LOG_FILES 50
#define MCFATAL(cat,x) CLOG(FATAL,cat) << x #define MCLOG_TYPE(level, cat, type, x) do { \
#define MCERROR(cat,x) CLOG(ERROR,cat) << x if (ELPP->vRegistry()->allowed(level, cat)) { \
#define MCWARNING(cat,x) CLOG(WARNING,cat) << x el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, type).construct(cat) << x; \
#define MCINFO(cat,x) CLOG(INFO,cat) << x } \
#define MCDEBUG(cat,x) CLOG(DEBUG,cat) << x } while (0)
#define MCTRACE(cat,x) CLOG(TRACE,cat) << x
#define MCLOG(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, el::base::DispatchAction::NormalLog, cat) << x #define MCLOG(level, cat, x) MCLOG_TYPE(level, cat, el::base::DispatchAction::NormalLog, x)
#define MCLOG_FILE(level,cat,x) ELPP_WRITE_LOG(el::base::Writer, level, el::base::DispatchAction::FileOnlyLog, cat) << x #define MCLOG_FILE(level, cat, x) MCLOG_TYPE(level, cat, el::base::DispatchAction::FileOnlyLog, x)
#define MCFATAL(cat,x) MCLOG(el::Level::Fatal,cat, x)
#define MCERROR(cat,x) MCLOG(el::Level::Error,cat, x)
#define MCWARNING(cat,x) MCLOG(el::Level::Warning,cat, x)
#define MCINFO(cat,x) MCLOG(el::Level::Info,cat, x)
#define MCDEBUG(cat,x) MCLOG(el::Level::Debug,cat, x)
#define MCTRACE(cat,x) MCLOG(el::Level::Trace,cat, x)
#define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat,"\033[1;" color "m" << x << "\033[0m") #define MCLOG_COLOR(level,cat,color,x) MCLOG(level,cat,"\033[1;" color "m" << x << "\033[0m")
#define MCLOG_RED(level,cat,x) MCLOG_COLOR(level,cat,"31",x) #define MCLOG_RED(level,cat,x) MCLOG_COLOR(level,cat,"31",x)

@ -431,7 +431,7 @@ namespace levin
} }
CRITICAL_REGION_END(); CRITICAL_REGION_END();
LOG_PRINT_L4("LEVIN_PACKET_RECIEVED. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]"); LOG_PRINT_L4("LEVIN_PACKET_RECEIVED. [len=" << head.m_cb << ", flags=" << head.m_flags << ", is_cmd=" << head.m_have_to_return_data <<", cmd_id = " << head.m_command << ", pr_v=" << head.m_protocol_version << ", uid=" << string_tools::get_str_from_guid_a(head.m_id) << "]");
if(is_request) if(is_request)
{ {

@ -416,7 +416,7 @@ public:
bool is_response = (m_oponent_protocol_ver == LEVIN_PROTOCOL_VER_1 && m_current_head.m_flags&LEVIN_PACKET_RESPONSE); bool is_response = (m_oponent_protocol_ver == LEVIN_PROTOCOL_VER_1 && m_current_head.m_flags&LEVIN_PACKET_RESPONSE);
MDEBUG(m_connection_context << "LEVIN_PACKET_RECIEVED. [len=" << m_current_head.m_cb MDEBUG(m_connection_context << "LEVIN_PACKET_RECEIVED. [len=" << m_current_head.m_cb
<< ", flags" << m_current_head.m_flags << ", flags" << m_current_head.m_flags
<< ", r?=" << m_current_head.m_have_to_return_data << ", r?=" << m_current_head.m_have_to_return_data
<<", cmd = " << m_current_head.m_command <<", cmd = " << m_current_head.m_command

@ -91,11 +91,15 @@ namespace misc_utils
*/ */
inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val) inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
{ {
val.clear();
val.reserve(std::distance(star_end_string, buf_end));
bool escape_mode = false; bool escape_mode = false;
std::string::const_iterator it = star_end_string; std::string::const_iterator it = star_end_string;
++it; ++it;
std::string::const_iterator fi = it;
while (fi != buf_end && *fi != '\\' && *fi != '\"')
++fi;
val.assign(it, fi);
val.reserve(std::distance(star_end_string, buf_end));
it = fi;
for(;it != buf_end;it++) for(;it != buf_end;it++)
{ {
if(escape_mode/*prev_ch == '\\'*/) if(escape_mode/*prev_ch == '\\'*/)

@ -117,16 +117,12 @@ namespace string_tools
return to_hex::string(to_byte_span(to_span(src))); return to_hex::string(to_byte_span(to_span(src)));
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template<class CharT> inline bool parse_hexstr_to_binbuff(const epee::span<const char> s, epee::span<char>& res)
bool parse_hexstr_to_binbuff(const std::basic_string<CharT>& s, std::basic_string<CharT>& res)
{ {
res.clear(); if (s.size() != res.size() * 2)
if (s.size() & 1) return false;
return false;
try unsigned char *dst = (unsigned char *)&res[0];
{
res.resize(s.size() / 2);
unsigned char *dst = (unsigned char *)res.data();
const unsigned char *src = (const unsigned char *)s.data(); const unsigned char *src = (const unsigned char *)s.data();
for(size_t i = 0; i < s.size(); i += 2) for(size_t i = 0; i < s.size(); i += 2)
{ {
@ -140,28 +136,15 @@ namespace string_tools
} }
return true; return true;
}
catch(...)
{
return false;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template<class t_pod_type> inline bool parse_hexstr_to_binbuff(const std::string& s, std::string& res)
bool parse_tpod_from_hex_string(const std::string& str_hash, t_pod_type& t_pod)
{ {
static_assert(std::is_pod<t_pod_type>::value, "expected pod type"); if (s.size() & 1)
std::string buf;
bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf);
if (!res || buf.size() != sizeof(t_pod_type))
{
return false; return false;
} res.resize(s.size() / 2);
else epee::span<char> rspan((char*)&res[0], res.size());
{ return parse_hexstr_to_binbuff(epee::to_span(s), rspan);
buf.copy(reinterpret_cast<char *>(&t_pod), sizeof(t_pod_type));
return true;
}
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
PUSH_WARNINGS PUSH_WARNINGS
@ -360,17 +343,10 @@ POP_WARNINGS
bool hex_to_pod(const std::string& hex_str, t_pod_type& s) bool hex_to_pod(const std::string& hex_str, t_pod_type& s)
{ {
static_assert(std::is_pod<t_pod_type>::value, "expected pod type"); static_assert(std::is_pod<t_pod_type>::value, "expected pod type");
std::string hex_str_tr = trim(hex_str);
if(sizeof(s)*2 != hex_str.size()) if(sizeof(s)*2 != hex_str.size())
return false; return false;
std::string bin_buff; epee::span<char> rspan((char*)&s, sizeof(s));
if(!parse_hexstr_to_binbuff(hex_str_tr, bin_buff)) return parse_hexstr_to_binbuff(epee::to_span(hex_str), rspan);
return false;
if(bin_buff.size()!=sizeof(s))
return false;
s = *(t_pod_type*)bin_buff.data();
return true;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
template<class t_pod_type> template<class t_pod_type>

@ -40,6 +40,9 @@
#include <atomic> #include <atomic>
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "mlocker"
// did an mlock operation previously fail? we only // did an mlock operation previously fail? we only
// want to log an error once and be done with it // want to log an error once and be done with it
static std::atomic<bool> previously_failed{ false }; static std::atomic<bool> previously_failed{ false };

@ -103,7 +103,7 @@ static const char *get_default_categories(int level)
categories = "*:WARNING,net:FATAL,net.http:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,stacktrace:INFO,logging:INFO,msgwriter:INFO"; categories = "*:WARNING,net:FATAL,net.http:FATAL,net.p2p:FATAL,net.cn:FATAL,global:INFO,verify:FATAL,stacktrace:INFO,logging:INFO,msgwriter:INFO";
break; break;
case 1: case 1:
categories = "*:INFO,global:INFO,stacktrace:INFO,logging:INFO,msgwriter:INFO"; categories = "*:INFO,global:INFO,stacktrace:INFO,logging:INFO,msgwriter:INFO,perf.*:DEBUG";
break; break;
case 2: case 2:
categories = "*:DEBUG"; categories = "*:DEBUG";

@ -14,8 +14,8 @@ IF (MSVC)
include_directories(SYSTEM platform/msvc) include_directories(SYSTEM platform/msvc)
ELSE() ELSE()
# set stuff for other systems # set stuff for other systems
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall -Werror") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wall")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Werror -Wno-reorder") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-reorder")
ENDIF() ENDIF()

@ -152,7 +152,7 @@ script: |
for i in ${HOSTS}; do for i in ${HOSTS}; do
export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH} export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
mkdir build && cd build mkdir build && cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=ON
make make
DISTNAME=monero-${i} DISTNAME=monero-${i}
mv bin ${DISTNAME} mv bin ${DISTNAME}

@ -1,163 +0,0 @@
#!/usr/bin/env python3
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
A script to check that the (Linux) executables produced by gitian only contain
allowed gcc, glibc and libstdc++ version symbols. This makes sure they are
still compatible with the minimum supported Linux distribution versions.
Example usage:
find ../gitian-builder/build -type f -executable | xargs python contrib/devtools/symbol-check.py
'''
import subprocess
import re
import sys
import os
# Debian 6.0.9 (Squeeze) has:
#
# - g++ version 4.4.5 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=g%2B%2B)
# - libc version 2.11.3 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libc6)
# - libstdc++ version 4.4.5 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libstdc%2B%2B6)
#
# Ubuntu 10.04.4 (Lucid Lynx) has:
#
# - g++ version 4.4.3 (http://packages.ubuntu.com/search?keywords=g%2B%2B&searchon=names&suite=lucid&section=all)
# - libc version 2.11.1 (http://packages.ubuntu.com/search?keywords=libc6&searchon=names&suite=lucid&section=all)
# - libstdc++ version 4.4.3 (http://packages.ubuntu.com/search?suite=lucid&section=all&arch=any&keywords=libstdc%2B%2B&searchon=names)
#
# Taking the minimum of these as our target.
#
# According to GNU ABI document (http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) this corresponds to:
# GCC 4.4.0: GCC_4.4.0
# GCC 4.4.2: GLIBCXX_3.4.13, CXXABI_1.3.3
# (glibc) GLIBC_2_11
#
MAX_VERSIONS = {
'GCC': (4,4,0),
'CXXABI': (1,3,3),
'GLIBCXX': (3,4,13),
'GLIBC': (2,11)
}
# See here for a description of _IO_stdin_used:
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109
# Ignore symbols that are exported as part of every executable
IGNORE_EXPORTS = {
'_edata', '_end', '_init', '__bss_start', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr'
}
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')
# Allowed NEEDED libraries
ALLOWED_LIBRARIES = {
# bitcoind and bitcoin-qt
'libgcc_s.so.1', # GCC base support
'libc.so.6', # C library
'libpthread.so.0', # threading
'libanl.so.1', # DNS resolve
'libm.so.6', # math library
'librt.so.1', # real-time (clock)
'ld-linux-x86-64.so.2', # 64-bit dynamic linker
'ld-linux.so.2', # 32-bit dynamic linker
# bitcoin-qt only
'libX11-xcb.so.1', # part of X11
'libX11.so.6', # part of X11
'libxcb.so.1', # part of X11
'libfontconfig.so.1', # font support
'libfreetype.so.6', # font parsing
'libdl.so.2' # programming interface to dynamic linker
}
class CPPFilt(object):
'''
Demangle C++ symbol names.
Use a pipe to the 'c++filt' command.
'''
def __init__(self):
self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
def __call__(self, mangled):
self.proc.stdin.write(mangled + '\n')
self.proc.stdin.flush()
return self.proc.stdout.readline().rstrip()
def close(self):
self.proc.stdin.close()
self.proc.stdout.close()
self.proc.wait()
def read_symbols(executable, imports=True):
'''
Parse an ELF executable and return a list of (symbol,version) tuples
for dynamic, imported symbols.
'''
p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip()))
syms = []
for line in stdout.splitlines():
line = line.split()
if len(line)>7 and re.match('[0-9]+:$', line[0]):
(sym, _, version) = line[7].partition('@')
is_import = line[6] == 'UND'
if version.startswith('@'):
version = version[1:]
if is_import == imports:
syms.append((sym, version))
return syms
def check_version(max_versions, version):
if '_' in version:
(lib, _, ver) = version.rpartition('_')
else:
lib = version
ver = '0'
ver = tuple([int(x) for x in ver.split('.')])
if not lib in max_versions:
return False
return ver <= max_versions[lib]
def read_libraries(filename):
p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
libraries = []
for line in stdout.splitlines():
tokens = line.split()
if len(tokens)>2 and tokens[1] == '(NEEDED)':
match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:]))
if match:
libraries.append(match.group(1))
else:
raise ValueError('Unparseable (NEEDED) specification')
return libraries
if __name__ == '__main__':
cppfilt = CPPFilt()
retval = 0
for filename in sys.argv[1:]:
# Check imported symbols
for sym,version in read_symbols(filename, True):
if version and not check_version(MAX_VERSIONS, version):
print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version))
retval = 1
# Check exported symbols
for sym,version in read_symbols(filename, False):
if sym in IGNORE_EXPORTS:
continue
print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym)))
retval = 1
# Check dependency libraries
for library_name in read_libraries(filename):
if library_name not in ALLOWED_LIBRARIES:
print('%s: NEEDED library %s is not allowed' % (filename, library_name))
retval = 1
sys.exit(retval)

@ -2130,24 +2130,23 @@ static int priority(Level level) {
return 7; return 7;
} }
bool VRegistry::allowed(Level level, const char* category) { bool VRegistry::allowed(Level level, const std::string &category) {
base::threading::ScopedLock scopedLock(lock()); base::threading::ScopedLock scopedLock(lock());
const std::string scategory = category; const std::map<std::string, int>::const_iterator it = m_cached_allowed_categories.find(category);
const std::map<std::string, int>::const_iterator it = m_cached_allowed_categories.find(scategory);
if (it != m_cached_allowed_categories.end()) if (it != m_cached_allowed_categories.end())
return priority(level) <= it->second; return priority(level) <= it->second;
if (m_categories.empty() || category == nullptr) { if (m_categories.empty()) {
return false; return false;
} else { } else {
std::vector<std::pair<std::string, Level>>::const_reverse_iterator it = m_categories.rbegin(); std::vector<std::pair<std::string, Level>>::const_reverse_iterator it = m_categories.rbegin();
for (; it != m_categories.rend(); ++it) { for (; it != m_categories.rend(); ++it) {
if (base::utils::Str::wildCardMatch(category, it->first.c_str())) { if (base::utils::Str::wildCardMatch(category.c_str(), it->first.c_str())) {
const int p = priority(it->second); const int p = priority(it->second);
m_cached_allowed_categories.insert(std::make_pair(std::move(scategory), p)); m_cached_allowed_categories.insert(std::make_pair(category, p));
return priority(level) <= p; return priority(level) <= p;
} }
} }
m_cached_allowed_categories.insert(std::make_pair(std::move(scategory), -1)); m_cached_allowed_categories.insert(std::make_pair(category, -1));
return false; return false;
} }
} }
@ -2694,6 +2693,12 @@ Writer& Writer::construct(int count, const char* loggerIds, ...) {
return *this; return *this;
} }
Writer& Writer::construct(const char *loggerId) {
initializeLogger(ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)));
m_messageBuilder.initialize(m_logger);
return *this;
}
void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool needLock) { void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool needLock) {
if (lookup) { if (lookup) {
m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically)); m_logger = ELPP->registeredLoggers()->get(loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically));
@ -2715,13 +2720,26 @@ void Writer::initializeLogger(const std::string& loggerId, bool lookup, bool nee
} }
if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) { if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) {
m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) : m_proceed = m_level == Level::Verbose ? m_logger->enabled(m_level) :
ELPP->vRegistry()->allowed(m_level, loggerId.c_str()); ELPP->vRegistry()->allowed(m_level, loggerId);
} else { } else {
m_proceed = m_logger->enabled(m_level); m_proceed = m_logger->enabled(m_level);
} }
} }
} }
void Writer::initializeLogger(Logger *logger, bool needLock) {
m_logger = logger;
if (m_logger == nullptr) {
m_proceed = false;
} else {
if (needLock) {
m_logger->acquireLock(); // This should not be unlocked by checking m_proceed because
// m_proceed can be changed by lines below
}
m_proceed = true;
}
}
void Writer::processDispatch() { void Writer::processDispatch() {
#if ELPP_LOGGING_ENABLED #if ELPP_LOGGING_ENABLED
if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) { if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {

@ -2463,7 +2463,7 @@ class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
void setModules(const char* modules); void setModules(const char* modules);
bool allowed(Level level, const char* category); bool allowed(Level level, const std::string &category);
bool allowed(base::type::VerboseLevel vlevel, const char* file); bool allowed(base::type::VerboseLevel vlevel, const char* file);
@ -3290,6 +3290,7 @@ class Writer : base::NoCopy {
Writer& construct(Logger* logger, bool needLock = true); Writer& construct(Logger* logger, bool needLock = true);
Writer& construct(int count, const char* loggerIds, ...); Writer& construct(int count, const char* loggerIds, ...);
Writer& construct(const char *loggerId);
protected: protected:
LogMessage* m_msg; LogMessage* m_msg;
Level m_level; Level m_level;
@ -3305,6 +3306,7 @@ class Writer : base::NoCopy {
friend class el::Helpers; friend class el::Helpers;
void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true); void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true);
void initializeLogger(Logger *logger, bool needLock = true);
void processDispatch(); void processDispatch();
void triggerDispatch(void); void triggerDispatch(void);
}; };

@ -34,11 +34,6 @@ if (WIN32 OR STATIC)
add_definitions(-DMINIUPNP_STATICLIB) add_definitions(-DMINIUPNP_STATICLIB)
endif () endif ()
# warnings are cleared only for GCC on Linux
if (NOT (MINGW OR APPLE OR FREEBSD OR OPENBSD OR DRAGONFLY))
add_compile_options("${WARNINGS_AS_ERRORS_FLAG}") # applies only to targets that follow
endif()
function (monero_private_headers group) function (monero_private_headers group)
source_group("${group}\\Private" source_group("${group}\\Private"
FILES FILES

@ -714,29 +714,6 @@ bool BlockchainBDB::for_all_outputs(std::function<bool(uint64_t amount, const cr
return ret; return ret;
} }
blobdata BlockchainBDB::output_to_blob(const tx_out& output) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
blobdata b;
if (!t_serializable_object_to_blob(output, b))
throw1(DB_ERROR("Error serializing output to blob"));
return b;
}
tx_out BlockchainBDB::output_from_blob(const blobdata& blob) const
{
LOG_PRINT_L3("BlockchainBDB::" << __func__);
std::stringstream ss;
ss << blob;
binary_archive<false> ba(ss);
tx_out o;
if (!(::serialization::serialize(ba, o)))
throw1(DB_ERROR("Error deserializing tx output blob"));
return o;
}
uint64_t BlockchainBDB::get_output_global_index(const uint64_t& amount, const uint64_t& index) uint64_t BlockchainBDB::get_output_global_index(const uint64_t& amount, const uint64_t& index)
{ {
LOG_PRINT_L3("BlockchainBDB::" << __func__); LOG_PRINT_L3("BlockchainBDB::" << __func__);
@ -1655,7 +1632,7 @@ output_data_t BlockchainBDB::get_output_key(const uint64_t& global_index) const
return v; return v;
} }
output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index) output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index) const
{ {
LOG_PRINT_L3("BlockchainBDB::" << __func__); LOG_PRINT_L3("BlockchainBDB::" << __func__);
check_open(); check_open();
@ -1664,7 +1641,7 @@ output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64
return get_output_key(glob_index); return get_output_key(glob_index);
} }
tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const
{ {
LOG_PRINT_L3("BlockchainBDB::" << __func__); LOG_PRINT_L3("BlockchainBDB::" << __func__);
std::vector < uint64_t > offsets; std::vector < uint64_t > offsets;

@ -391,24 +391,6 @@ private:
virtual void check_hard_fork_info(); virtual void check_hard_fork_info();
virtual void drop_hard_fork_info(); virtual void drop_hard_fork_info();
/**
* @brief convert a tx output to a blob for storage
*
* @param output the output to convert
*
* @return the resultant blob
*/
blobdata output_to_blob(const tx_out& output) const;
/**
* @brief convert a tx output blob to a tx output
*
* @param blob the blob to convert
*
* @return the resultant tx output
*/
tx_out output_from_blob(const blobdata& blob) const;
/** /**
* @brief get the global index of the index-th output of the given amount * @brief get the global index of the index-th output of the given amount
* *

@ -170,7 +170,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash, tx_prunable_hash); uint64_t tx_id = add_transaction_data(blk_hash, tx, tx_hash, tx_prunable_hash);
std::vector<uint64_t> amount_output_indices; std::vector<uint64_t> amount_output_indices(tx.vout.size());
// iterate tx.vout using indices instead of C++11 foreach syntax because // iterate tx.vout using indices instead of C++11 foreach syntax because
// we need the index // we need the index
@ -183,13 +183,13 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti
cryptonote::tx_out vout = tx.vout[i]; cryptonote::tx_out vout = tx.vout[i];
rct::key commitment = rct::zeroCommit(vout.amount); rct::key commitment = rct::zeroCommit(vout.amount);
vout.amount = 0; vout.amount = 0;
amount_output_indices.push_back(add_output(tx_hash, vout, i, tx.unlock_time, amount_output_indices[i] = add_output(tx_hash, vout, i, tx.unlock_time,
&commitment)); &commitment);
} }
else else
{ {
amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time, amount_output_indices[i] = add_output(tx_hash, tx.vout[i], i, tx.unlock_time,
tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL)); tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL);
} }
} }
add_tx_amount_output_indices(tx_id, amount_output_indices); add_tx_amount_output_indices(tx_id, amount_output_indices);

@ -1258,7 +1258,7 @@ public:
* *
* @return the requested output data * @return the requested output data
*/ */
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0; virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) const = 0;
/** /**
* @brief gets an output's tx hash and index * @brief gets an output's tx hash and index
@ -1310,7 +1310,7 @@ public:
* @param offsets a list of amount-specific output indices * @param offsets a list of amount-specific output indices
* @param outputs return-by-reference a list of outputs' metadata * @param outputs return-by-reference a list of outputs' metadata
*/ */
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) = 0; 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 = 0;
/* /*
* FIXME: Need to check with git blame and ask what this does to * FIXME: Need to check with git blame and ask what this does to

@ -456,6 +456,12 @@ inline int lmdb_txn_renew(MDB_txn *txn)
return res; return res;
} }
inline void BlockchainLMDB::check_open() const
{
if (!m_open)
throw0(DB_ERROR("DB operation attempted on a not-open DB instance"));
}
void BlockchainLMDB::do_resize(uint64_t increase_size) void BlockchainLMDB::do_resize(uint64_t increase_size)
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@ -1166,36 +1172,6 @@ void BlockchainLMDB::remove_spent_key(const crypto::key_image& k_image)
} }
} }
blobdata BlockchainLMDB::output_to_blob(const tx_out& output) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
blobdata b;
if (!t_serializable_object_to_blob(output, b))
throw1(DB_ERROR("Error serializing output to blob"));
return b;
}
tx_out BlockchainLMDB::output_from_blob(const blobdata& blob) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
std::stringstream ss;
ss << blob;
binary_archive<false> ba(ss);
tx_out o;
if (!(::serialization::serialize(ba, o)))
throw1(DB_ERROR("Error deserializing tx output blob"));
return o;
}
void BlockchainLMDB::check_open() const
{
// LOG_PRINT_L3("BlockchainLMDB::" << __func__);
if (!m_open)
throw0(DB_ERROR("DB operation attempted on a not-open DB instance"));
}
BlockchainLMDB::~BlockchainLMDB() BlockchainLMDB::~BlockchainLMDB()
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@ -2559,7 +2535,7 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const
return num_elems; return num_elems;
} }
output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index) output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open(); check_open();
@ -3192,7 +3168,7 @@ uint64_t BlockchainLMDB::add_block(const block& blk, size_t block_weight, const
check_open(); check_open();
uint64_t m_height = height(); uint64_t m_height = height();
if (m_height % 1000 == 0) if (m_height % 1024 == 0)
{ {
// for batch mode, DB resize check is done at start of batch transaction // for batch mode, DB resize check is done at start of batch transaction
if (! m_batch_active && need_resize()) if (! m_batch_active && need_resize())
@ -3266,7 +3242,7 @@ void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector<uint6
TXN_POSTFIX_RDONLY(); TXN_POSTFIX_RDONLY();
} }
void BlockchainLMDB::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) void BlockchainLMDB::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) const
{ {
if (amounts.size() != 1 && amounts.size() != offsets.size()) if (amounts.size() != 1 && amounts.size() != offsets.size())
throw0(DB_ERROR("Invalid sizes of amounts and offets")); throw0(DB_ERROR("Invalid sizes of amounts and offets"));

@ -242,8 +242,8 @@ public:
virtual uint64_t get_num_outputs(const uint64_t& amount) const; 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); virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) 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); 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; virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
virtual void get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices, virtual void get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
@ -359,25 +359,7 @@ private:
virtual void check_hard_fork_info(); virtual void check_hard_fork_info();
virtual void drop_hard_fork_info(); virtual void drop_hard_fork_info();
/** inline void check_open() const;
* @brief convert a tx output to a blob for storage
*
* @param output the output to convert
*
* @return the resultant blob
*/
blobdata output_to_blob(const tx_out& output) const;
/**
* @brief convert a tx output blob to a tx output
*
* @param blob the blob to convert
*
* @return the resultant tx output
*/
tx_out output_from_blob(const blobdata& blob) const;
void check_open() const;
virtual bool is_read_only() const; virtual bool is_read_only() const;

@ -39,7 +39,7 @@ foreach(BLOB_NAME checkpoints testnet_blocks stagenet_blocks)
cd ${CMAKE_CURRENT_BINARY_DIR} && cd ${CMAKE_CURRENT_BINARY_DIR} &&
echo "'#include\t<stddef.h>'" > ${OUTPUT_C_SOURCE} && echo "'#include\t<stddef.h>'" > ${OUTPUT_C_SOURCE} &&
echo "'const\tunsigned\tchar\t${BLOB_NAME}[]={'" >> ${OUTPUT_C_SOURCE} && echo "'const\tunsigned\tchar\t${BLOB_NAME}[]={'" >> ${OUTPUT_C_SOURCE} &&
od -v -An -tu1 ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_DAT_FILE} | sed -e "'s/[0-9]\\{1,\\}/&,/g'" -e "'$$s/.$$//'" >> ${OUTPUT_C_SOURCE} && od -v -An -tx1 ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_DAT_FILE} | sed -e "'s/[0-9a-fA-F]\\{1,\\}/0x&,/g'" -e "'$$s/.$$//'" >> ${OUTPUT_C_SOURCE} &&
echo "'};'" >> ${OUTPUT_C_SOURCE} && echo "'};'" >> ${OUTPUT_C_SOURCE} &&
echo "'const\tsize_t\t${BLOB_NAME}_len\t=\tsizeof(${BLOB_NAME});'" >> ${OUTPUT_C_SOURCE} echo "'const\tsize_t\t${BLOB_NAME}_len\t=\tsizeof(${BLOB_NAME});'" >> ${OUTPUT_C_SOURCE}
) )

@ -74,7 +74,7 @@ namespace cryptonote
bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str) bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
{ {
crypto::hash h = crypto::null_hash; crypto::hash h = crypto::null_hash;
bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h); bool r = epee::string_tools::hex_to_pod(hash_str, h);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!"); CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!");
// return false if adding at a height we already have AND the hash is different // return false if adding at a height we already have AND the hash is different
@ -283,7 +283,7 @@ namespace cryptonote
// parse the second part as crypto::hash, // parse the second part as crypto::hash,
// if this fails move on to the next record // if this fails move on to the next record
std::string hashStr = record.substr(pos + 1); std::string hashStr = record.substr(pos + 1);
if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash)) if (!epee::string_tools::hex_to_pod(hashStr, hash))
{ {
continue; continue;
} }

@ -50,6 +50,10 @@ if (STACK_TRACE)
list(APPEND common_sources stack_trace.cpp) list(APPEND common_sources stack_trace.cpp)
endif() endif()
if (BACKCOMPAT)
list(APPEND common_sources compat/glibc_compat.cpp)
endif()
set(common_headers) set(common_headers)
set(common_private_headers set(common_private_headers

@ -0,0 +1,98 @@
#include <cstddef>
#include <cstdint>
#include <strings.h>
#include <string.h>
#include <glob.h>
#include <unistd.h>
#include <fnmatch.h>
#if defined(HAVE_SYS_SELECT_H)
#include <sys/select.h>
#endif
// Prior to GLIBC_2.14, memcpy was aliased to memmove.
extern "C" void* memmove(void* a, const void* b, size_t c);
//extern "C" void* memset(void* a, int b, long unsigned int c);
extern "C" void* memcpy(void* a, const void* b, size_t c)
{
return memmove(a, b, c);
}
extern "C" void __chk_fail(void) __attribute__((__noreturn__));
#if defined(__i386__) || defined(__arm__)
extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);
extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
{
int32_t c1 = 0, c2 = 0;
int64_t uu = u, vv = v;
int64_t w;
int64_t r;
if (uu < 0) {
c1 = ~c1, c2 = ~c2, uu = -uu;
}
if (vv < 0) {
c1 = ~c1, vv = -vv;
}
w = __udivmoddi4(uu, vv, (uint64_t*)&r);
if (c1)
w = -w;
if (c2)
r = -r;
*rp = r;
return w;
}
#endif
/* glibc-internal users use __explicit_bzero_chk, and explicit_bzero
redirects to that. */
#undef explicit_bzero
/* Set LEN bytes of S to 0. The compiler will not delete a call to
this function, even if S is dead after the call. */
void
explicit_bzero (void *s, size_t len)
{
memset (s, '\0', len);
/* Compiler barrier. */
asm volatile ("" ::: "memory");
}
// Redefine explicit_bzero_chk
void
__explicit_bzero_chk (void *dst, size_t len, size_t dstlen)
{
/* Inline __memset_chk to avoid a PLT reference to __memset_chk. */
if (__glibc_unlikely (dstlen < len))
__chk_fail ();
memset (dst, '\0', len);
/* Compiler barrier. */
asm volatile ("" ::: "memory");
}
/* libc-internal references use the hidden
__explicit_bzero_chk_internal symbol. This is necessary if
__explicit_bzero_chk is implemented as an IFUNC because some
targets do not support hidden references to IFUNC symbols. */
#define strong_alias (__explicit_bzero_chk, __explicit_bzero_chk_internal)
#undef glob
extern "C" int glob_old(const char * pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob);
#ifdef __i386__
__asm__(".symver glob_old,glob@GLIBC_2.1");
#elif defined(__amd64__)
__asm__(".symver glob_old,glob@GLIBC_2.2.5");
#elif defined(__arm__)
__asm(".symver glob_old,glob@GLIBC_2.4");
#elif defined(__aarch64__)
__asm__(".symver glob_old,glob@GLIBC_2.17");
#endif
extern "C" int __wrap_glob(const char * pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob)
{
return glob_old(pattern, flags, errfunc, pglob);
}

@ -33,6 +33,13 @@
#undef MONERO_DEFAULT_LOG_CATEGORY #undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "perf" #define MONERO_DEFAULT_LOG_CATEGORY "perf"
#define PERF_LOG_ALWAYS(level, cat, x) \
el::base::Writer(level, __FILE__, __LINE__, ELPP_FUNC, el::base::DispatchAction::FileOnlyLog).construct(cat) << x
#define PERF_LOG(level, cat, x) \
do { \
if (ELPP->vRegistry()->allowed(level, cat)) PERF_LOG_ALWAYS(level, cat, x); \
} while(0)
namespace tools namespace tools
{ {
uint64_t get_tick_count() uint64_t get_tick_count()
@ -106,9 +113,11 @@ PerformanceTimer::PerformanceTimer(bool paused): started(true), paused(paused)
LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l): PerformanceTimer(), name(s), cat(cat), unit(unit), level(l) LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l): PerformanceTimer(), name(s), cat(cat), unit(unit), level(l)
{ {
const bool log = ELPP->vRegistry()->allowed(level, cat.c_str());
if (!performance_timers) if (!performance_timers)
{ {
MCLOG(level, cat.c_str(), "PERF ----------"); if (log)
PERF_LOG_ALWAYS(level, cat.c_str(), "PERF ----------");
performance_timers = new std::vector<LoggingPerformanceTimer*>(); performance_timers = new std::vector<LoggingPerformanceTimer*>();
performance_timers->reserve(16); // how deep before realloc performance_timers->reserve(16); // how deep before realloc
} }
@ -117,8 +126,11 @@ LoggingPerformanceTimer::LoggingPerformanceTimer(const std::string &s, const std
LoggingPerformanceTimer *pt = performance_timers->back(); LoggingPerformanceTimer *pt = performance_timers->back();
if (!pt->started && !pt->paused) if (!pt->started && !pt->paused)
{ {
size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size; if (log)
MCLOG(pt->level, cat.c_str(), "PERF " << std::string((size-1) * 2, ' ') << " " << pt->name); {
size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused) ++size;
PERF_LOG_ALWAYS(pt->level, cat.c_str(), "PERF " << std::string((size-1) * 2, ' ') << " " << pt->name);
}
pt->started = true; pt->started = true;
} }
} }
@ -135,10 +147,14 @@ LoggingPerformanceTimer::~LoggingPerformanceTimer()
{ {
pause(); pause();
performance_timers->pop_back(); performance_timers->pop_back();
char s[12]; const bool log = ELPP->vRegistry()->allowed(level, cat.c_str());
snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit))); if (log)
size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size; {
MCLOG(level, cat.c_str(), "PERF " << s << std::string(size * 2, ' ') << " " << name); char s[12];
snprintf(s, sizeof(s), "%8llu ", (unsigned long long)(ticks_to_ns(ticks) / (1000000000 / unit)));
size_t size = 0; for (const auto *tmp: *performance_timers) if (!tmp->paused || tmp==this) ++size;
PERF_LOG_ALWAYS(level, cat.c_str(), "PERF " << s << std::string(size * 2, ' ') << " " << name);
}
if (performance_timers->empty()) if (performance_timers->empty())
{ {
delete performance_timers; delete performance_timers;
@ -162,4 +178,20 @@ void PerformanceTimer::resume()
paused = false; paused = false;
} }
void PerformanceTimer::reset()
{
if (paused)
ticks = 0;
else
ticks = get_tick_count();
}
uint64_t PerformanceTimer::value() const
{
uint64_t v = ticks;
if (!paused)
v = get_tick_count() - v;
return ticks_to_ns(v);
}
} }

@ -51,8 +51,8 @@ public:
~PerformanceTimer(); ~PerformanceTimer();
void pause(); void pause();
void resume(); void resume();
void reset();
uint64_t value() const { return ticks; } uint64_t value() const;
protected: protected:
uint64_t ticks; uint64_t ticks;
@ -63,7 +63,7 @@ protected:
class LoggingPerformanceTimer: public PerformanceTimer class LoggingPerformanceTimer: public PerformanceTimer
{ {
public: public:
LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l = el::Level::Debug); LoggingPerformanceTimer(const std::string &s, const std::string &cat, uint64_t unit, el::Level l = el::Level::Info);
~LoggingPerformanceTimer(); ~LoggingPerformanceTimer();
private: private:

@ -35,6 +35,7 @@
#include <windows.h> #include <windows.h>
#else #else
#include <sys/wait.h> #include <sys/wait.h>
#include <signal.h>
#endif #endif
#include "misc_log_ex.h" #include "misc_log_ex.h"
@ -114,7 +115,10 @@ int spawn(const char *filename, const std::vector<std::string>& args, bool wait)
if (pid > 0) if (pid > 0)
{ {
if (!wait) if (!wait)
{
signal(SIGCHLD, SIG_IGN);
return 0; return 0;
}
while (1) while (1)
{ {

@ -82,6 +82,32 @@ using namespace epee;
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <openssl/sha.h> #include <openssl/sha.h>
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "util"
namespace
{
#ifndef _WIN32
static int flock_exnb(int fd)
{
struct flock fl;
int ret;
memset(&fl, 0, sizeof(fl));
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
ret = fcntl(fd, F_SETLK, &fl);
if (ret < 0)
MERROR("Error locking fd " << fd << ": " << errno << " (" << strerror(errno) << ")");
return ret;
}
#endif
}
namespace tools namespace tools
{ {
std::function<void(int)> signal_handler::m_handler; std::function<void(int)> signal_handler::m_handler;
@ -182,7 +208,7 @@ namespace tools
struct stat wstats = {}; struct stat wstats = {};
if (fstat(fdw, std::addressof(wstats)) == 0 && if (fstat(fdw, std::addressof(wstats)) == 0 &&
rstats.st_dev == wstats.st_dev && rstats.st_ino == wstats.st_ino && rstats.st_dev == wstats.st_dev && rstats.st_ino == wstats.st_ino &&
flock(fdw, (LOCK_EX | LOCK_NB)) == 0 && ftruncate(fdw, 0) == 0) flock_exnb(fdw) == 0 && ftruncate(fdw, 0) == 0)
{ {
std::FILE* file = fdopen(fdw, "w"); std::FILE* file = fdopen(fdw, "w");
if (file) return {file, std::move(name)}; if (file) return {file, std::move(name)};
@ -235,10 +261,10 @@ namespace tools
MERROR("Failed to open " << filename << ": " << std::error_code(GetLastError(), std::system_category())); MERROR("Failed to open " << filename << ": " << std::error_code(GetLastError(), std::system_category()));
} }
#else #else
m_fd = open(filename.c_str(), O_RDONLY | O_CREAT | O_CLOEXEC, 0666); m_fd = open(filename.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0666);
if (m_fd != -1) if (m_fd != -1)
{ {
if (flock(m_fd, LOCK_EX | LOCK_NB) == -1) if (flock_exnb(m_fd) == -1)
{ {
MERROR("Failed to lock " << filename << ": " << std::strerror(errno)); MERROR("Failed to lock " << filename << ": " << std::strerror(errno));
close(m_fd); close(m_fd);

@ -211,6 +211,8 @@ namespace cryptonote
void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); } void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); }
bool is_blob_size_valid() const { return blob_size_valid.load(std::memory_order_acquire); } bool is_blob_size_valid() const { return blob_size_valid.load(std::memory_order_acquire); }
void set_blob_size_valid(bool v) const { blob_size_valid.store(v,std::memory_order_release); } void set_blob_size_valid(bool v) const { blob_size_valid.store(v,std::memory_order_release); }
void set_hash(const crypto::hash &h) { hash = h; set_hash_valid(true); }
void set_blob_size(size_t sz) { blob_size = sz; set_blob_size_valid(true); }
BEGIN_SERIALIZE_OBJECT() BEGIN_SERIALIZE_OBJECT()
if (!typename Archive<W>::is_saving()) if (!typename Archive<W>::is_saving())

@ -204,6 +204,7 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data"); CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data");
tx.invalidate_hashes(); tx.invalidate_hashes();
tx.set_blob_size(tx_blob.size());
return true; return true;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
@ -401,11 +402,19 @@ namespace cryptonote
//--------------------------------------------------------------- //---------------------------------------------------------------
uint64_t get_transaction_weight(const transaction &tx) uint64_t get_transaction_weight(const transaction &tx)
{ {
std::ostringstream s; size_t blob_size;
binary_archive<true> a(s); if (tx.is_blob_size_valid())
::serialization::serialize(a, const_cast<transaction&>(tx)); {
const cryptonote::blobdata blob = s.str(); blob_size = tx.blob_size;
return get_transaction_weight(tx, blob.size()); }
else
{
std::ostringstream s;
binary_archive<true> a(s);
::serialization::serialize(a, const_cast<transaction&>(tx));
blob_size = s.str().size();
}
return get_transaction_weight(tx, blob_size);
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
bool get_tx_fee(const transaction& tx, uint64_t & fee) bool get_tx_fee(const transaction& tx, uint64_t & fee)

@ -128,6 +128,11 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
Blockchain::~Blockchain()
{
deinit();
}
//------------------------------------------------------------------
bool Blockchain::have_tx(const crypto::hash &id) const bool Blockchain::have_tx(const crypto::hash &id) const
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
@ -507,15 +512,13 @@ bool Blockchain::deinit()
// as this should be called if handling a SIGSEGV, need to check // as this should be called if handling a SIGSEGV, need to check
// if m_db is a NULL pointer (and thus may have caused the illegal // if m_db is a NULL pointer (and thus may have caused the illegal
// memory operation), otherwise we may cause a loop. // memory operation), otherwise we may cause a loop.
if (m_db == NULL)
{
throw DB_ERROR("The db pointer is null in Blockchain, the blockchain may be corrupt!");
}
try try
{ {
m_db->close(); if (m_db)
MTRACE("Local blockchain read/write activity stopped successfully"); {
m_db->close();
MTRACE("Local blockchain read/write activity stopped successfully");
}
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
@ -1270,7 +1273,9 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
uint64_t already_generated_coins; uint64_t already_generated_coins;
uint64_t pool_cookie; uint64_t pool_cookie;
CRITICAL_REGION_BEGIN(m_blockchain_lock); m_tx_pool.lock();
const auto unlock_guard = epee::misc_utils::create_scope_leave_handler([&]() { m_tx_pool.unlock(); });
CRITICAL_REGION_LOCAL(m_blockchain_lock);
height = m_db->height(); height = m_db->height();
if (m_btc_valid) { if (m_btc_valid) {
// The pool cookie is atomic. The lack of locking is OK, as if it changes // The pool cookie is atomic. The lack of locking is OK, as if it changes
@ -1306,8 +1311,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
median_weight = m_current_block_cumul_weight_limit / 2; median_weight = m_current_block_cumul_weight_limit / 2;
already_generated_coins = m_db->get_block_already_generated_coins(height - 1); already_generated_coins = m_db->get_block_already_generated_coins(height - 1);
CRITICAL_REGION_END();
size_t txs_weight; size_t txs_weight;
uint64_t fee; uint64_t fee;
if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, m_hardfork->get_current_version())) if (!m_tx_pool.fill_block_template(b, median_weight, already_generated_coins, txs_weight, fee, expected_reward, m_hardfork->get_current_version()))
@ -1318,7 +1321,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) #if defined(DEBUG_CREATE_BLOCK_TEMPLATE)
size_t real_txs_weight = 0; size_t real_txs_weight = 0;
uint64_t real_fee = 0; uint64_t real_fee = 0;
CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock);
for(crypto::hash &cur_hash: b.tx_hashes) for(crypto::hash &cur_hash: b.tx_hashes)
{ {
auto cur_res = m_tx_pool.m_transactions.find(cur_hash); auto cur_res = m_tx_pool.m_transactions.find(cur_hash);
@ -1362,7 +1364,6 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
{ {
LOG_ERROR("Creating block template: error: wrongly calculated fee"); LOG_ERROR("Creating block template: error: wrongly calculated fee");
} }
CRITICAL_REGION_END();
MDEBUG("Creating block template: height " << height << MDEBUG("Creating block template: height " << height <<
", median weight " << median_weight << ", median weight " << median_weight <<
", already generated coins " << already_generated_coins << ", already generated coins " << already_generated_coins <<

@ -120,6 +120,11 @@ namespace cryptonote
*/ */
Blockchain(tx_memory_pool& tx_pool); Blockchain(tx_memory_pool& tx_pool);
/**
* @brief Blockchain destructor
*/
~Blockchain();
/** /**
* @brief Initialize the Blockchain state * @brief Initialize the Blockchain state
* *

@ -480,6 +480,10 @@ namespace cryptonote
MERROR("Failed to parse tx from txpool"); MERROR("Failed to parse tx from txpool");
return false; return false;
} }
else
{
tx.set_hash(id);
}
tx_weight = meta.weight; tx_weight = meta.weight;
fee = meta.fee; fee = meta.fee;
relayed = meta.relayed; relayed = meta.relayed;
@ -659,7 +663,8 @@ namespace cryptonote
// continue // continue
return true; return true;
} }
txs.push_back(tx); tx.set_hash(txid);
txs.push_back(std::move(tx));
return true; return true;
}, true, include_unrelayed_txes); }, true, include_unrelayed_txes);
} }
@ -782,6 +787,7 @@ namespace cryptonote
// continue // continue
return true; return true;
} }
tx.set_hash(txid);
txi.tx_json = obj_to_json_str(tx); txi.tx_json = obj_to_json_str(tx);
txi.blob_size = bd->size(); txi.blob_size = bd->size();
txi.weight = meta.weight; txi.weight = meta.weight;
@ -798,7 +804,7 @@ namespace cryptonote
txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0; txi.last_relayed_time = include_sensitive_data ? meta.last_relayed_time : 0;
txi.do_not_relay = meta.do_not_relay; txi.do_not_relay = meta.do_not_relay;
txi.double_spend_seen = meta.double_spend_seen; txi.double_spend_seen = meta.double_spend_seen;
tx_infos.push_back(txi); tx_infos.push_back(std::move(txi));
return true; return true;
}, true, include_sensitive_data); }, true, include_sensitive_data);
@ -847,14 +853,13 @@ namespace cryptonote
m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){ m_blockchain.for_all_txpool_txes([&tx_infos, key_image_infos](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
cryptonote::rpc::tx_in_pool txi; cryptonote::rpc::tx_in_pool txi;
txi.tx_hash = txid; txi.tx_hash = txid;
transaction tx; if (!parse_and_validate_tx_from_blob(*bd, txi.tx))
if (!parse_and_validate_tx_from_blob(*bd, tx))
{ {
MERROR("Failed to parse tx from txpool"); MERROR("Failed to parse tx from txpool");
// continue // continue
return true; return true;
} }
txi.tx = tx; txi.tx.set_hash(txid);
txi.blob_size = bd->size(); txi.blob_size = bd->size();
txi.weight = meta.weight; txi.weight = meta.weight;
txi.fee = meta.fee; txi.fee = meta.fee;
@ -881,7 +886,7 @@ namespace cryptonote
} }
const crypto::key_image& k_image = kee.first; const crypto::key_image& k_image = kee.first;
key_image_infos[k_image] = tx_hashes; key_image_infos[k_image] = std::move(tx_hashes);
} }
return true; return true;
} }
@ -990,21 +995,23 @@ namespace cryptonote
{ {
struct transction_parser struct transction_parser
{ {
transction_parser(const cryptonote::blobdata &txblob, transaction &tx): txblob(txblob), tx(tx), parsed(false) {} transction_parser(const cryptonote::blobdata &txblob, const crypto::hash &txid, transaction &tx): txblob(txblob), txid(txid), tx(tx), parsed(false) {}
cryptonote::transaction &operator()() cryptonote::transaction &operator()()
{ {
if (!parsed) if (!parsed)
{ {
if (!parse_and_validate_tx_from_blob(txblob, tx)) if (!parse_and_validate_tx_from_blob(txblob, tx))
throw std::runtime_error("failed to parse transaction blob"); throw std::runtime_error("failed to parse transaction blob");
tx.set_hash(txid);
parsed = true; parsed = true;
} }
return tx; return tx;
} }
const cryptonote::blobdata &txblob; const cryptonote::blobdata &txblob;
const crypto::hash &txid;
transaction &tx; transaction &tx;
bool parsed; bool parsed;
} lazy_tx(txblob, tx); } lazy_tx(txblob, txid, tx);
//not the best implementation at this time, sorry :( //not the best implementation at this time, sorry :(
//check is ring_signature already checked ? //check is ring_signature already checked ?

@ -131,6 +131,7 @@ namespace cryptonote
bool should_download_next_span(cryptonote_connection_context& context) const; bool should_download_next_span(cryptonote_connection_context& context) const;
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans); void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
bool kick_idle_peers(); bool kick_idle_peers();
bool check_standby_peers();
int try_add_next_blocks(cryptonote_connection_context &context); int try_add_next_blocks(cryptonote_connection_context &context);
t_core& m_core; t_core& m_core;
@ -143,6 +144,7 @@ namespace cryptonote
boost::mutex m_sync_lock; boost::mutex m_sync_lock;
block_queue m_block_queue; block_queue m_block_queue;
epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker; epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker;
epee::math_helper::once_a_time_milliseconds<100> m_standby_checker;
boost::mutex m_buffer_mutex; boost::mutex m_buffer_mutex;
double get_avg_block_size(); double get_avg_block_size();

@ -1208,6 +1208,7 @@ skip:
bool t_cryptonote_protocol_handler<t_core>::on_idle() bool t_cryptonote_protocol_handler<t_core>::on_idle()
{ {
m_idle_peer_kicker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::kick_idle_peers, this)); m_idle_peer_kicker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::kick_idle_peers, this));
m_standby_checker.do_call(boost::bind(&t_cryptonote_protocol_handler<t_core>::check_standby_peers, this));
return m_core.on_idle(); return m_core.on_idle();
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
@ -1243,6 +1244,22 @@ skip:
} }
//------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------
template<class t_core> template<class t_core>
bool t_cryptonote_protocol_handler<t_core>::check_standby_peers()
{
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
{
if (context.m_state == cryptonote_connection_context::state_standby)
{
LOG_PRINT_CCONTEXT_L2("requesting callback");
++context.m_callback_request_count;
m_p2p->request_callback(context);
}
return true;
});
return true;
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context) int t_cryptonote_protocol_handler<t_core>::handle_request_chain(int command, NOTIFY_REQUEST_CHAIN::request& arg, cryptonote_connection_context& context)
{ {
MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks"); MLOG_P2P_MESSAGE("Received NOTIFY_REQUEST_CHAIN (" << arg.block_ids.size() << " blocks");
@ -1336,14 +1353,13 @@ skip:
bool start_from_current_chain = false; bool start_from_current_chain = false;
if (!force_next_span) if (!force_next_span)
{ {
bool first = true; do
while (1)
{ {
size_t nblocks = m_block_queue.get_num_filled_spans(); size_t nblocks = m_block_queue.get_num_filled_spans();
size_t size = m_block_queue.get_data_size(); size_t size = m_block_queue.get_data_size();
if (nblocks < BLOCK_QUEUE_NBLOCKS_THRESHOLD || size < BLOCK_QUEUE_SIZE_THRESHOLD) if (nblocks < BLOCK_QUEUE_NBLOCKS_THRESHOLD || size < BLOCK_QUEUE_SIZE_THRESHOLD)
{ {
if (!first) if (context.m_state != cryptonote_connection_context::state_standby)
{ {
LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", resuming"); LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", resuming");
} }
@ -1366,10 +1382,9 @@ skip:
break; break;
} }
if (first) if (context.m_state != cryptonote_connection_context::state_standby)
{ {
LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", pausing"); LOG_DEBUG_CC(context, "Block queue is " << nblocks << " and " << size << ", pausing");
first = false;
context.m_state = cryptonote_connection_context::state_standby; context.m_state = cryptonote_connection_context::state_standby;
} }
@ -1383,13 +1398,8 @@ skip:
return true; return true;
} }
for (size_t n = 0; n < 50; ++n) return true;
{ } while(0);
if (m_stopping)
return true;
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
}
}
context.m_state = cryptonote_connection_context::state_synchronizing; context.m_state = cryptonote_connection_context::state_synchronizing;
} }

@ -67,14 +67,6 @@ set(trezor_private_headers)
if(DEVICE_TREZOR_READY) if(DEVICE_TREZOR_READY)
message(STATUS "Trezor support enabled") message(STATUS "Trezor support enabled")
add_definitions(-DPROTOBUF_INLINE_NOT_IN_HEADERS=0)
set(TREZOR_LIBUSB_LIBRARIES "")
if(LibUSB_COMPILE_TEST_PASSED)
list(APPEND TREZOR_LIBUSB_LIBRARIES ${LibUSB_LIBRARIES})
message(STATUS "Trezor compatible LibUSB found at: ${LibUSB_INCLUDE_DIRS}")
endif()
monero_private_headers(device_trezor monero_private_headers(device_trezor
${device_private_headers}) ${device_private_headers})

@ -50,8 +50,8 @@ namespace Language
class Singleton class Singleton
{ {
Singleton() {} Singleton() {}
Singleton(Singleton &s) {} Singleton(Singleton &s) = delete;
Singleton& operator=(const Singleton&) {} Singleton& operator=(const Singleton&) = delete;
public: public:
static T* instance() static T* instance()
{ {

@ -194,12 +194,12 @@ namespace nodetool
const boost::program_options::variables_map& vm const boost::program_options::variables_map& vm
); );
bool idle_worker(); bool idle_worker();
bool handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context); bool handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context);
bool get_local_node_data(basic_node_data& node_data); bool get_local_node_data(basic_node_data& node_data);
//bool get_local_handshake_data(handshake_data& hshd); //bool get_local_handshake_data(handshake_data& hshd);
bool merge_peerlist_with_local(const std::list<peerlist_entry>& bs); bool merge_peerlist_with_local(const std::vector<peerlist_entry>& bs);
bool fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta); bool fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta);
bool connections_maker(); bool connections_maker();
bool peer_sync_idle_maker(); bool peer_sync_idle_maker();

@ -1365,7 +1365,7 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::fix_time_delta(std::list<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta) bool node_server<t_payload_net_handler>::fix_time_delta(std::vector<peerlist_entry>& local_peerlist, time_t local_time, int64_t& delta)
{ {
//fix time delta //fix time delta
time_t now = 0; time_t now = 0;
@ -1385,10 +1385,10 @@ namespace nodetool
} }
//----------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::list<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context) bool node_server<t_payload_net_handler>::handle_remote_peerlist(const std::vector<peerlist_entry>& peerlist, time_t local_time, const epee::net_utils::connection_context_base& context)
{ {
int64_t delta = 0; int64_t delta = 0;
std::list<peerlist_entry> peerlist_ = peerlist; std::vector<peerlist_entry> peerlist_ = peerlist;
if(!fix_time_delta(peerlist_, local_time, delta)) if(!fix_time_delta(peerlist_, local_time, delta))
return false; return false;
LOG_DEBUG_CC(context, "REMOTE PEERLIST: TIME_DELTA: " << delta << ", remote peerlist size=" << peerlist_.size()); LOG_DEBUG_CC(context, "REMOTE PEERLIST: TIME_DELTA: " << delta << ", remote peerlist size=" << peerlist_.size());
@ -1770,8 +1770,8 @@ namespace nodetool
template<class t_payload_net_handler> template<class t_payload_net_handler>
bool node_server<t_payload_net_handler>::log_peerlist() bool node_server<t_payload_net_handler>::log_peerlist()
{ {
std::list<peerlist_entry> pl_white; std::vector<peerlist_entry> pl_white;
std::list<peerlist_entry> pl_gray; std::vector<peerlist_entry> pl_gray;
m_peerlist.get_peerlist_full(pl_gray, pl_white); m_peerlist.get_peerlist_full(pl_gray, pl_white);
MINFO(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_white) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) ); MINFO(ENDL << "Peerlist white:" << ENDL << print_peerlist_to_string(pl_white) << ENDL << "Peerlist gray:" << ENDL << print_peerlist_to_string(pl_gray) );
return true; return true;

@ -68,9 +68,9 @@ namespace nodetool
bool deinit(); bool deinit();
size_t get_white_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_white.size();} size_t get_white_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_white.size();}
size_t get_gray_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_gray.size();} size_t get_gray_peers_count(){CRITICAL_REGION_LOCAL(m_peerlist_lock); return m_peers_gray.size();}
bool merge_peerlist(const std::list<peerlist_entry>& outer_bs); bool merge_peerlist(const std::vector<peerlist_entry>& outer_bs);
bool get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE); bool get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth = P2P_DEFAULT_PEERS_IN_HANDSHAKE);
bool get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white); bool get_peerlist_full(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white);
bool get_white_peer_by_index(peerlist_entry& p, size_t i); bool get_white_peer_by_index(peerlist_entry& p, size_t i);
bool get_gray_peer_by_index(peerlist_entry& p, size_t i); bool get_gray_peer_by_index(peerlist_entry& p, size_t i);
bool append_with_peer_white(const peerlist_entry& pr); bool append_with_peer_white(const peerlist_entry& pr);
@ -265,7 +265,7 @@ namespace nodetool
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
inline inline
bool peerlist_manager::merge_peerlist(const std::list<peerlist_entry>& outer_bs) bool peerlist_manager::merge_peerlist(const std::vector<peerlist_entry>& outer_bs)
{ {
CRITICAL_REGION_LOCAL(m_peerlist_lock); CRITICAL_REGION_LOCAL(m_peerlist_lock);
for(const peerlist_entry& be: outer_bs) for(const peerlist_entry& be: outer_bs)
@ -315,12 +315,13 @@ namespace nodetool
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
inline inline
bool peerlist_manager::get_peerlist_head(std::list<peerlist_entry>& bs_head, uint32_t depth) bool peerlist_manager::get_peerlist_head(std::vector<peerlist_entry>& bs_head, uint32_t depth)
{ {
CRITICAL_REGION_LOCAL(m_peerlist_lock); CRITICAL_REGION_LOCAL(m_peerlist_lock);
peers_indexed::index<by_time>::type& by_time_index=m_peers_white.get<by_time>(); peers_indexed::index<by_time>::type& by_time_index=m_peers_white.get<by_time>();
uint32_t cnt = 0; uint32_t cnt = 0;
bs_head.reserve(depth);
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index)) for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index))
{ {
if(!vl.last_seen) if(!vl.last_seen)
@ -335,16 +336,18 @@ namespace nodetool
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
inline inline
bool peerlist_manager::get_peerlist_full(std::list<peerlist_entry>& pl_gray, std::list<peerlist_entry>& pl_white) bool peerlist_manager::get_peerlist_full(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white)
{ {
CRITICAL_REGION_LOCAL(m_peerlist_lock); CRITICAL_REGION_LOCAL(m_peerlist_lock);
peers_indexed::index<by_time>::type& by_time_index_gr=m_peers_gray.get<by_time>(); peers_indexed::index<by_time>::type& by_time_index_gr=m_peers_gray.get<by_time>();
pl_gray.resize(pl_gray.size() + by_time_index_gr.size());
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_gr)) for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_gr))
{ {
pl_gray.push_back(vl); pl_gray.push_back(vl);
} }
peers_indexed::index<by_time>::type& by_time_index_wt=m_peers_white.get<by_time>(); peers_indexed::index<by_time>::type& by_time_index_wt=m_peers_white.get<by_time>();
pl_white.resize(pl_white.size() + by_time_index_wt.size());
for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_wt)) for(const peers_indexed::value_type& vl: boost::adaptors::reverse(by_time_index_wt))
{ {
pl_white.push_back(vl); pl_white.push_back(vl);

@ -114,7 +114,7 @@ namespace nodetool
#pragma pack(pop) #pragma pack(pop)
inline inline
std::string print_peerlist_to_string(const std::list<peerlist_entry>& pl) std::string print_peerlist_to_string(const std::vector<peerlist_entry>& pl)
{ {
time_t now_time = 0; time_t now_time = 0;
time(&now_time); time(&now_time);
@ -189,7 +189,7 @@ namespace nodetool
{ {
basic_node_data node_data; basic_node_data node_data;
t_playload_type payload_data; t_playload_type payload_data;
std::list<peerlist_entry> local_peerlist_new; std::vector<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(node_data) KV_SERIALIZE(node_data)
@ -198,7 +198,7 @@ namespace nodetool
{ {
// saving: save both, so old and new peers can understand it // saving: save both, so old and new peers can understand it
KV_SERIALIZE(local_peerlist_new) KV_SERIALIZE(local_peerlist_new)
std::list<peerlist_entry_base<network_address_old>> local_peerlist; std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
for (const auto &p: this_ref.local_peerlist_new) for (const auto &p: this_ref.local_peerlist_new)
{ {
if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID) if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@ -217,7 +217,7 @@ namespace nodetool
// loading: load old list only if there is no new one // loading: load old list only if there is no new one
if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new")) if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
{ {
std::list<peerlist_entry_base<network_address_old>> local_peerlist; std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist) for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
@ -248,7 +248,7 @@ namespace nodetool
{ {
uint64_t local_time; uint64_t local_time;
t_playload_type payload_data; t_playload_type payload_data;
std::list<peerlist_entry> local_peerlist_new; std::vector<peerlist_entry> local_peerlist_new;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(local_time) KV_SERIALIZE(local_time)
@ -257,7 +257,7 @@ namespace nodetool
{ {
// saving: save both, so old and new peers can understand it // saving: save both, so old and new peers can understand it
KV_SERIALIZE(local_peerlist_new) KV_SERIALIZE(local_peerlist_new)
std::list<peerlist_entry_base<network_address_old>> local_peerlist; std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
for (const auto &p: this_ref.local_peerlist_new) for (const auto &p: this_ref.local_peerlist_new)
{ {
if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID) if (p.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@ -276,7 +276,7 @@ namespace nodetool
// loading: load old list only if there is no new one // loading: load old list only if there is no new one
if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new")) if (!epee::serialization::selector<is_store>::serialize(this_ref.local_peerlist_new, stg, hparent_section, "local_peerlist_new"))
{ {
std::list<peerlist_entry_base<network_address_old>> local_peerlist; std::vector<peerlist_entry_base<network_address_old>> local_peerlist;
epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist"); epee::serialization::selector<is_store>::serialize_stl_container_pod_val_as_blob(local_peerlist, stg, hparent_section, "local_peerlist");
for (const auto &p: local_peerlist) for (const auto &p: local_peerlist)
((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen})); ((response&)this_ref).local_peerlist_new.push_back(peerlist_entry({epee::net_utils::ipv4_network_address(p.adr.ip, p.adr.port), p.id, p.last_seen}));
@ -389,9 +389,9 @@ namespace nodetool
struct response struct response
{ {
std::list<peerlist_entry> local_peerlist_white; std::vector<peerlist_entry> local_peerlist_white;
std::list<peerlist_entry> local_peerlist_gray; std::vector<peerlist_entry> local_peerlist_gray;
std::list<connection_entry> connections_list; std::vector<connection_entry> connections_list;
peerid_type my_id; peerid_type my_id;
uint64_t local_time; uint64_t local_time;
BEGIN_KV_SERIALIZE_MAP() BEGIN_KV_SERIALIZE_MAP()

@ -857,11 +857,11 @@ namespace cryptonote
bool core_rpc_server::on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res) bool core_rpc_server::on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res)
{ {
PERF_TIMER(on_get_peer_list); PERF_TIMER(on_get_peer_list);
std::list<nodetool::peerlist_entry> white_list; std::vector<nodetool::peerlist_entry> white_list;
std::list<nodetool::peerlist_entry> gray_list; std::vector<nodetool::peerlist_entry> gray_list;
m_p2p.get_peerlist_manager().get_peerlist_full(gray_list, white_list); m_p2p.get_peerlist_manager().get_peerlist_full(gray_list, white_list);
res.white_list.reserve(white_list.size());
for (auto & entry : white_list) for (auto & entry : white_list)
{ {
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID) if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)
@ -871,6 +871,7 @@ namespace cryptonote
res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen); res.white_list.emplace_back(entry.id, entry.adr.str(), entry.last_seen);
} }
res.gray_list.reserve(gray_list.size());
for (auto & entry : gray_list) for (auto & entry : gray_list)
{ {
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID) if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::ID)

@ -2474,6 +2474,19 @@ bool simple_wallet::set_ignore_fractional_outputs(const std::vector<std::string>
return true; return true;
} }
bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
parse_bool_and_use(args[1], [&](bool r) {
m_wallet->track_uses(r);
m_wallet->rewrite(m_wallet_file, pwd_container->password());
});
}
return true;
}
bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std::vector<std::string>()*/) bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{ {
const auto pwd_container = get_and_verify_password(); const auto pwd_container = get_and_verify_password();
@ -3031,6 +3044,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second; success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second;
success_msg_writer() << "segregation-height = " << m_wallet->segregation_height(); success_msg_writer() << "segregation-height = " << m_wallet->segregation_height();
success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs(); success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs();
success_msg_writer() << "track-uses = " << m_wallet->track_uses();
success_msg_writer() << "device_name = " << m_wallet->device_name(); success_msg_writer() << "device_name = " << m_wallet->device_name();
return true; return true;
} }
@ -3087,6 +3101,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>")); CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>"));
CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer")); CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("track-uses", set_track_uses, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>")); CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
} }
fail_msg_writer() << tr("set: unrecognized argument(s)"); fail_msg_writer() << tr("set: unrecognized argument(s)");
@ -4814,6 +4829,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
bool filter = false; bool filter = false;
bool available = false; bool available = false;
bool verbose = false; bool verbose = false;
bool uses = false;
if (local_args.size() > 0) if (local_args.size() > 0)
{ {
if (local_args[0] == "available") if (local_args[0] == "available")
@ -4829,12 +4845,22 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
local_args.erase(local_args.begin()); local_args.erase(local_args.begin());
} }
} }
if (local_args.size() > 0 && local_args[0] == "verbose") while (local_args.size() > 0)
{ {
verbose = true; if (local_args[0] == "verbose")
verbose = true;
else if (local_args[0] == "uses")
uses = true;
else
{
fail_msg_writer() << tr("Invalid keyword: ") << local_args.front();
break;
}
local_args.erase(local_args.begin()); local_args.erase(local_args.begin());
} }
const uint64_t blockchain_height = m_wallet->get_blockchain_current_height();
PAUSE_READLINE(); PAUSE_READLINE();
std::set<uint32_t> subaddr_indices; std::set<uint32_t> subaddr_indices;
@ -4868,9 +4894,16 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
verbose_string = (boost::format("%68s%68s") % tr("pubkey") % tr("key image")).str(); verbose_string = (boost::format("%68s%68s") % tr("pubkey") % tr("key image")).str();
message_writer() << boost::format("%21s%8s%12s%8s%16s%68s%16s%s") % tr("amount") % tr("spent") % tr("unlocked") % tr("ringct") % tr("global index") % tr("tx id") % tr("addr index") % verbose_string; message_writer() << boost::format("%21s%8s%12s%8s%16s%68s%16s%s") % tr("amount") % tr("spent") % tr("unlocked") % tr("ringct") % tr("global index") % tr("tx id") % tr("addr index") % verbose_string;
} }
std::string verbose_string; std::string extra_string;
if (verbose) if (verbose)
verbose_string = (boost::format("%68s%68s") % td.get_public_key() % (td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : td.m_key_image_partial ? (epee::string_tools::pod_to_hex(td.m_key_image) + "/p") : std::string(64, '?'))).str(); extra_string += (boost::format("%68s%68s") % td.get_public_key() % (td.m_key_image_known ? epee::string_tools::pod_to_hex(td.m_key_image) : td.m_key_image_partial ? (epee::string_tools::pod_to_hex(td.m_key_image) + "/p") : std::string(64, '?'))).str();
if (uses)
{
std::vector<uint64_t> heights;
for (const auto &e: td.m_uses) heights.push_back(e.first);
const std::pair<std::string, std::string> line = show_outputs_line(heights, blockchain_height, td.m_spent_height);
extra_string += tr("Heights: ") + line.first + "\n" + line.second;
}
message_writer(td.m_spent ? console_color_magenta : console_color_green, false) << message_writer(td.m_spent ? console_color_magenta : console_color_green, false) <<
boost::format("%21s%8s%12s%8s%16u%68s%16u%s") % boost::format("%21s%8s%12s%8s%16u%68s%16u%s") %
print_money(td.amount()) % print_money(td.amount()) %
@ -4880,7 +4913,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
td.m_global_output_index % td.m_global_output_index %
td.m_txid % td.m_txid %
td.m_subaddr_index.minor % td.m_subaddr_index.minor %
verbose_string; extra_string;
++transfers_found; ++transfers_found;
} }
} }
@ -4978,6 +5011,33 @@ bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
return true; return true;
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
std::pair<std::string, std::string> simple_wallet::show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height) const
{
std::stringstream ostr;
for (uint64_t h: heights)
blockchain_height = std::max(blockchain_height, h);
for (size_t j = 0; j < heights.size(); ++j)
ostr << (heights[j] == highlight_height ? " *" : " ") << heights[j];
// visualize the distribution, using the code by moneroexamples onion-monero-viewer
const uint64_t resolution = 79;
std::string ring_str(resolution, '_');
for (size_t j = 0; j < heights.size(); ++j)
{
uint64_t pos = (heights[j] * resolution) / blockchain_height;
ring_str[pos] = 'o';
}
if (highlight_height < blockchain_height)
{
uint64_t pos = (highlight_height * resolution) / blockchain_height;
ring_str[pos] = '*';
}
return std::make_pair(ostr.str(), ring_str);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr) bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr)
{ {
uint32_t version; uint32_t version;
@ -5048,21 +5108,18 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
} }
} }
ostr << tr("\nOriginating block heights: "); ostr << tr("\nOriginating block heights: ");
for (size_t j = 0; j < absolute_offsets.size(); ++j)
ostr << tr(j == source.real_output ? " *" : " ") << res.outs[j].height;
spent_key_height[i] = res.outs[source.real_output].height; spent_key_height[i] = res.outs[source.real_output].height;
spent_key_txid [i] = res.outs[source.real_output].txid; spent_key_txid [i] = res.outs[source.real_output].txid;
// visualize the distribution, using the code by moneroexamples onion-monero-viewer std::vector<uint64_t> heights(absolute_offsets.size(), 0);
const uint64_t resolution = 79; uint64_t highlight_height = std::numeric_limits<uint64_t>::max();
std::string ring_str(resolution, '_');
for (size_t j = 0; j < absolute_offsets.size(); ++j) for (size_t j = 0; j < absolute_offsets.size(); ++j)
{ {
uint64_t pos = (res.outs[j].height * resolution) / blockchain_height; heights[j] = res.outs[j].height;
ring_str[pos] = 'o'; if (j == source.real_output)
highlight_height = heights[j];
} }
uint64_t pos = (res.outs[source.real_output].height * resolution) / blockchain_height; std::pair<std::string, std::string> ring_str = show_outputs_line(heights, highlight_height);
ring_str[pos] = '*'; ostr << ring_str.first << tr("\n|") << ring_str.second << tr("|\n");
ostr << tr("\n|") << ring_str << tr("|\n");
} }
// warn if rings contain keys originating from the same tx or temporally very close block heights // warn if rings contain keys originating from the same tx or temporally very close block heights
bool are_keys_from_same_tx = false; bool are_keys_from_same_tx = false;
@ -6268,8 +6325,18 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
local_args.pop_back(); local_args.pop_back();
} }
// get amount and pop // get amount and pop
amount_str = local_args.back(); uint64_t amount;
local_args.pop_back(); bool ok = cryptonote::parse_amount(amount, local_args.back());
if (ok && amount != 0)
{
amount_str = local_args.back();
local_args.pop_back();
}
else
{
fail_msg_writer() << tr("amount is wrong: ") << local_args.back() << ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits<uint64_t>::max());
return true;
}
// push back address, amount, payment id // push back address, amount, payment id
std::string address_str; std::string address_str;
if (m_wallet->nettype() != cryptonote::MAINNET) if (m_wallet->nettype() != cryptonote::MAINNET)

@ -142,6 +142,7 @@ namespace cryptonote
bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>()); bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>());
bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>()); bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>());
bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>()); bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>());
bool set_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>()); bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>()); bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool help_advanced(const std::vector<std::string> &args = std::vector<std::string>()); bool help_advanced(const std::vector<std::string> &args = std::vector<std::string>());
@ -249,6 +250,7 @@ namespace cryptonote
bool print_seed(bool encrypted); bool print_seed(bool encrypted);
void key_images_sync_intern(); void key_images_sync_intern();
void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money); void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money);
std::pair<std::string, std::string> show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height = std::numeric_limits<uint64_t>::max()) const;
struct transfer_view struct transfer_view
{ {

@ -139,6 +139,12 @@ if (BUILD_GUI_DEPS)
endif() endif()
install(TARGETS wallet_merged install(TARGETS wallet_merged
ARCHIVE DESTINATION ${lib_folder}) ARCHIVE DESTINATION ${lib_folder})
install(FILES ${TREZOR_DEP_LIBS}
DESTINATION ${lib_folder})
file(WRITE "trezor_link_flags.txt" ${TREZOR_DEP_LINKER})
install(FILES "trezor_link_flags.txt"
DESTINATION ${lib_folder})
endif() endif()
add_subdirectory(api) add_subdirectory(api)

@ -1141,7 +1141,7 @@ std::string WalletImpl::getSubaddressLabel(uint32_t accountIndex, uint32_t addre
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
LOG_ERROR("Error getting subaddress label: ") << e.what(); LOG_ERROR("Error getting subaddress label: " << e.what());
setStatusError(string(tr("Failed to get subaddress label: ")) + e.what()); setStatusError(string(tr("Failed to get subaddress label: ")) + e.what());
return ""; return "";
} }
@ -1154,7 +1154,7 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex
} }
catch (const std::exception &e) catch (const std::exception &e)
{ {
LOG_ERROR("Error setting subaddress label: ") << e.what(); LOG_ERROR("Error setting subaddress label: " << e.what());
setStatusError(string(tr("Failed to set subaddress label: ")) + e.what()); setStatusError(string(tr("Failed to set subaddress label: ")) + e.what());
} }
} }
@ -1171,7 +1171,7 @@ string WalletImpl::getMultisigInfo() const {
clearStatus(); clearStatus();
return m_wallet->get_multisig_info(); return m_wallet->get_multisig_info();
} catch (const exception& e) { } catch (const exception& e) {
LOG_ERROR("Error on generating multisig info: ") << e.what(); LOG_ERROR("Error on generating multisig info: " << e.what());
setStatusError(string(tr("Failed to get multisig info: ")) + e.what()); setStatusError(string(tr("Failed to get multisig info: ")) + e.what());
} }
@ -1188,7 +1188,7 @@ string WalletImpl::makeMultisig(const vector<string>& info, uint32_t threshold)
return m_wallet->make_multisig(epee::wipeable_string(m_password), info, threshold); return m_wallet->make_multisig(epee::wipeable_string(m_password), info, threshold);
} catch (const exception& e) { } catch (const exception& e) {
LOG_ERROR("Error on making multisig wallet: ") << e.what(); LOG_ERROR("Error on making multisig wallet: " << e.what());
setStatusError(string(tr("Failed to make multisig: ")) + e.what()); setStatusError(string(tr("Failed to make multisig: ")) + e.what());
} }
@ -1202,7 +1202,7 @@ std::string WalletImpl::exchangeMultisigKeys(const std::vector<std::string> &inf
return m_wallet->exchange_multisig_keys(epee::wipeable_string(m_password), info); return m_wallet->exchange_multisig_keys(epee::wipeable_string(m_password), info);
} catch (const exception& e) { } catch (const exception& e) {
LOG_ERROR("Error on exchanging multisig keys: ") << e.what(); LOG_ERROR("Error on exchanging multisig keys: " << e.what());
setStatusError(string(tr("Failed to make multisig: ")) + e.what()); setStatusError(string(tr("Failed to make multisig: ")) + e.what());
} }
@ -1220,7 +1220,7 @@ bool WalletImpl::finalizeMultisig(const vector<string>& extraMultisigInfo) {
setStatusError(tr("Failed to finalize multisig wallet creation")); setStatusError(tr("Failed to finalize multisig wallet creation"));
} catch (const exception& e) { } catch (const exception& e) {
LOG_ERROR("Error on finalizing multisig wallet creation: ") << e.what(); LOG_ERROR("Error on finalizing multisig wallet creation: " << e.what());
setStatusError(string(tr("Failed to finalize multisig wallet creation: ")) + e.what()); setStatusError(string(tr("Failed to finalize multisig wallet creation: ")) + e.what());
} }
@ -1236,7 +1236,7 @@ bool WalletImpl::exportMultisigImages(string& images) {
images = epee::string_tools::buff_to_hex_nodelimer(blob); images = epee::string_tools::buff_to_hex_nodelimer(blob);
return true; return true;
} catch (const exception& e) { } catch (const exception& e) {
LOG_ERROR("Error on exporting multisig images: ") << e.what(); LOG_ERROR("Error on exporting multisig images: " << e.what());
setStatusError(string(tr("Failed to export multisig images: ")) + e.what()); setStatusError(string(tr("Failed to export multisig images: ")) + e.what());
} }
@ -1264,7 +1264,7 @@ size_t WalletImpl::importMultisigImages(const vector<string>& images) {
return m_wallet->import_multisig(blobs); return m_wallet->import_multisig(blobs);
} catch (const exception& e) { } catch (const exception& e) {
LOG_ERROR("Error on importing multisig images: ") << e.what(); LOG_ERROR("Error on importing multisig images: " << e.what());
setStatusError(string(tr("Failed to import multisig images: ")) + e.what()); setStatusError(string(tr("Failed to import multisig images: ")) + e.what());
} }
@ -1278,7 +1278,7 @@ bool WalletImpl::hasMultisigPartialKeyImages() const {
return m_wallet->has_multisig_partial_key_images(); return m_wallet->has_multisig_partial_key_images();
} catch (const exception& e) { } catch (const exception& e) {
LOG_ERROR("Error on checking for partial multisig key images: ") << e.what(); LOG_ERROR("Error on checking for partial multisig key images: " << e.what());
setStatusError(string(tr("Failed to check for partial multisig key images: ")) + e.what()); setStatusError(string(tr("Failed to check for partial multisig key images: ")) + e.what());
} }
@ -1306,7 +1306,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat
return ptx; return ptx;
} catch (exception& e) { } catch (exception& e) {
LOG_ERROR("Error on restoring multisig transaction: ") << e.what(); LOG_ERROR("Error on restoring multisig transaction: " << e.what());
setStatusError(string(tr("Failed to restore multisig transaction: ")) + e.what()); setStatusError(string(tr("Failed to restore multisig transaction: ")) + e.what());
} }

@ -125,7 +125,7 @@ void message_store::set_signer(const multisig_wallet_state &state,
const boost::optional<std::string> &transport_address, const boost::optional<std::string> &transport_address,
const boost::optional<cryptonote::account_public_address> monero_address) const boost::optional<cryptonote::account_public_address> monero_address)
{ {
THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index); THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
authorized_signer &m = m_signers[index]; authorized_signer &m = m_signers[index];
if (label) if (label)
{ {
@ -146,7 +146,7 @@ void message_store::set_signer(const multisig_wallet_state &state,
const authorized_signer &message_store::get_signer(uint32_t index) const const authorized_signer &message_store::get_signer(uint32_t index) const
{ {
THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index); THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
return m_signers[index]; return m_signers[index];
} }
@ -201,7 +201,7 @@ void message_store::unpack_signer_config(const multisig_wallet_state &state, con
THROW_WALLET_EXCEPTION_IF(true, tools::error::wallet_internal_error, "Invalid structure of signer config"); THROW_WALLET_EXCEPTION_IF(true, tools::error::wallet_internal_error, "Invalid structure of signer config");
} }
uint32_t num_signers = (uint32_t)signers.size(); uint32_t num_signers = (uint32_t)signers.size();
THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + num_signers); THROW_WALLET_EXCEPTION_IF(num_signers != m_num_authorized_signers, tools::error::wallet_internal_error, "Wrong number of signers in config: " + std::to_string(num_signers));
} }
void message_store::process_signer_config(const multisig_wallet_state &state, const std::string &signer_config) void message_store::process_signer_config(const multisig_wallet_state &state, const std::string &signer_config)
@ -424,7 +424,7 @@ void message_store::setup_signer_for_auto_config(uint32_t index, const std::stri
// auto-config parameters. In the wallet of somebody using the token to send auto-config // auto-config parameters. In the wallet of somebody using the token to send auto-config
// data the auto-config parameters are stored in the "me" signer and taken from there // data the auto-config parameters are stored in the "me" signer and taken from there
// to send that data. // to send that data.
THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + index); THROW_WALLET_EXCEPTION_IF(index >= m_num_authorized_signers, tools::error::wallet_internal_error, "Invalid signer index " + std::to_string(index));
authorized_signer &m = m_signers[index]; authorized_signer &m = m_signers[index];
m.auto_config_token = token; m.auto_config_token = token;
crypto::hash_to_scalar(token.data(), token.size(), m.auto_config_secret_key); crypto::hash_to_scalar(token.data(), token.size(), m.auto_config_secret_key);
@ -506,7 +506,7 @@ void message_store::process_wallet_created_data(const multisig_wallet_state &sta
break; break;
default: default:
THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Illegal message type " + (uint32_t)type); THROW_WALLET_EXCEPTION(tools::error::wallet_internal_error, "Illegal message type " + std::to_string((uint32_t)type));
break; break;
} }
} }
@ -573,7 +573,7 @@ size_t message_store::get_message_index_by_id(uint32_t id) const
{ {
size_t index; size_t index;
bool found = get_message_index_by_id(id, index); bool found = get_message_index_by_id(id, index);
THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + id); THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + std::to_string(id));
return index; return index;
} }
@ -601,7 +601,7 @@ message message_store::get_message_by_id(uint32_t id) const
{ {
message m; message m;
bool found = get_message_by_id(id, m); bool found = get_message_by_id(id, m);
THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + id); THROW_WALLET_EXCEPTION_IF(!found, tools::error::wallet_internal_error, "Invalid message id " + std::to_string(id));
return m; return m;
} }

@ -894,6 +894,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
m_key_reuse_mitigation2(false), m_key_reuse_mitigation2(false),
m_segregation_height(0), m_segregation_height(0),
m_ignore_fractional_outputs(true), m_ignore_fractional_outputs(true),
m_track_uses(false),
m_is_initialized(false), m_is_initialized(false),
m_kdf_rounds(kdf_rounds), m_kdf_rounds(kdf_rounds),
is_old_file_format(false), is_old_file_format(false),
@ -1448,8 +1449,9 @@ void wallet2::cache_tx_data(const cryptonote::transaction& tx, const crypto::has
} }
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data) void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{ {
PERF_TIMER(process_new_transaction);
// In this function, tx (probably) only contains the base information // In this function, tx (probably) only contains the base information
// (that is, the prunable stuff may or may not be included) // (that is, the prunable stuff may or may not be included)
if (!miner_tx && !pool) if (!miner_tx && !pool)
@ -1686,6 +1688,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
if (!m_multisig && !m_watch_only) if (!m_multisig && !m_watch_only)
m_key_images[td.m_key_image] = m_transfers.size()-1; 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; m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
if (output_tracker_cache)
(*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = m_transfers.size() - 1;
if (m_multisig) if (m_multisig)
{ {
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info, THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@ -1751,6 +1755,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_mask = rct::identity(); td.m_mask = rct::identity();
td.m_rct = false; td.m_rct = false;
} }
if (output_tracker_cache)
(*output_tracker_cache)[std::make_pair(tx.vout[o].amount, td.m_global_output_index)] = kit->second;
if (m_multisig) if (m_multisig)
{ {
THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info, THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info,
@ -1782,11 +1788,12 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
{ {
if(in.type() != typeid(cryptonote::txin_to_key)) if(in.type() != typeid(cryptonote::txin_to_key))
continue; continue;
auto it = m_key_images.find(boost::get<cryptonote::txin_to_key>(in).k_image); const cryptonote::txin_to_key &in_to_key = boost::get<cryptonote::txin_to_key>(in);
auto it = m_key_images.find(in_to_key.k_image);
if(it != m_key_images.end()) if(it != m_key_images.end())
{ {
transfer_details& td = m_transfers[it->second]; transfer_details& td = m_transfers[it->second];
uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount; uint64_t amount = in_to_key.amount;
if (amount > 0) if (amount > 0)
{ {
if(amount != td.amount()) if(amount != td.amount())
@ -1817,6 +1824,34 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index); m_callback->on_money_spent(height, txid, tx, amount, tx, td.m_subaddr_index);
} }
} }
if (!pool && m_track_uses)
{
PERF_TIMER(track_uses);
const uint64_t amount = in_to_key.amount;
std::vector<uint64_t> offsets = cryptonote::relative_output_offsets_to_absolute(in_to_key.key_offsets);
if (output_tracker_cache)
{
for (uint64_t offset: offsets)
{
const std::map<std::pair<uint64_t, uint64_t>, size_t>::const_iterator i = output_tracker_cache->find(std::make_pair(amount, offset));
if (i != output_tracker_cache->end())
{
size_t idx = i->second;
THROW_WALLET_EXCEPTION_IF(idx >= m_transfers.size(), error::wallet_internal_error, "Output tracker cache index out of range");
m_transfers[idx].m_uses.push_back(std::make_pair(height, txid));
}
}
}
else for (transfer_details &td: m_transfers)
{
if (amount != in_to_key.amount)
continue;
for (uint64_t offset: offsets)
if (offset == td.m_global_output_index)
td.m_uses.push_back(std::make_pair(height, txid));
}
}
} }
uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee; uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee;
@ -1999,7 +2034,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
add_rings(tx); add_rings(tx);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset) void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{ {
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error, THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 1 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
"block transactions=" + std::to_string(bche.txs.size()) + "block transactions=" + std::to_string(bche.txs.size()) +
@ -2012,7 +2047,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
{ {
TIME_MEASURE_START(miner_tx_handle_time); TIME_MEASURE_START(miner_tx_handle_time);
if (m_refresh_type != RefreshNoCoinbase) if (m_refresh_type != RefreshNoCoinbase)
process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset]); process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, parsed_block.o_indices.indices[0].indices, height, b.timestamp, true, false, false, tx_cache_data[tx_cache_data_offset], output_tracker_cache);
++tx_cache_data_offset; ++tx_cache_data_offset;
TIME_MEASURE_FINISH(miner_tx_handle_time); TIME_MEASURE_FINISH(miner_tx_handle_time);
@ -2021,7 +2056,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b, const cry
THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block"); THROW_WALLET_EXCEPTION_IF(bche.txs.size() != parsed_block.txes.size(), error::wallet_internal_error, "Wrong amount of transactions for block");
for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx) for (size_t idx = 0; idx < b.tx_hashes.size(); ++idx)
{ {
process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++]); process_new_transaction(b.tx_hashes[idx], parsed_block.txes[idx], parsed_block.o_indices.indices[idx+1].indices, height, b.timestamp, false, false, false, tx_cache_data[tx_cache_data_offset++], output_tracker_cache);
} }
TIME_MEASURE_FINISH(txs_handle_time); TIME_MEASURE_FINISH(txs_handle_time);
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx); m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
@ -2119,7 +2154,7 @@ void wallet2::pull_hashes(uint64_t start_height, uint64_t &blocks_start_height,
hashes = std::move(res.m_block_ids); hashes = std::move(res.m_block_ids);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added) void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache)
{ {
size_t current_index = start_height; size_t current_index = start_height;
blocks_added = 0; blocks_added = 0;
@ -2226,7 +2261,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
if(current_index >= m_blockchain.size()) if(current_index >= m_blockchain.size())
{ {
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset); process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
++blocks_added; ++blocks_added;
} }
else if(bl_id != m_blockchain[current_index]) else if(bl_id != m_blockchain[current_index])
@ -2238,7 +2273,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry
string_tools::pod_to_hex(m_blockchain[current_index])); string_tools::pod_to_hex(m_blockchain[current_index]));
detach_blockchain(current_index); detach_blockchain(current_index);
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset); process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, tx_cache_data, tx_cache_data_offset, output_tracker_cache);
} }
else else
{ {
@ -2670,6 +2705,17 @@ bool wallet2::delete_address_book_row(std::size_t row_id) {
return true; return true;
} }
//----------------------------------------------------------------------------------------------------
std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> wallet2::create_output_tracker_cache() const
{
std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> cache{new std::map<std::pair<uint64_t, uint64_t>, size_t>()};
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details &td = m_transfers[i];
(*cache)[std::make_pair(td.is_rct() ? 0 : td.amount(), td.m_global_output_index)] = i;
}
return cache;
}
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money) void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blocks_fetched, bool& received_money)
{ {
@ -2717,6 +2763,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
std::vector<cryptonote::block_complete_entry> blocks; std::vector<cryptonote::block_complete_entry> blocks;
std::vector<parsed_block> parsed_blocks; std::vector<parsed_block> parsed_blocks;
bool refreshed = false; bool refreshed = false;
std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> output_tracker_cache;
// pull the first set of blocks // pull the first set of blocks
get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY); get_short_chain_history(short_chain_history, (m_first_refresh_done || trusted_daemon) ? 1 : FIRST_REFRESH_GRANULARITY);
@ -2770,7 +2817,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
{ {
try try
{ {
process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks); process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks, output_tracker_cache.get());
} }
catch (const tools::error::out_of_hashchain_bounds_error&) catch (const tools::error::out_of_hashchain_bounds_error&)
{ {
@ -2813,6 +2860,11 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo
throw std::runtime_error("proxy exception in refresh thread"); throw std::runtime_error("proxy exception in refresh thread");
} }
// if we've got at least 10 blocks to refresh, assume we're starting
// a long refresh, and setup a tracking output cache if we need to
if (m_track_uses && !output_tracker_cache && next_blocks.size() >= 10)
output_tracker_cache = create_output_tracker_cache();
// switch to the new blocks from the daemon // switch to the new blocks from the daemon
blocks_start_height = next_blocks_start_height; blocks_start_height = next_blocks_start_height;
blocks = std::move(next_blocks); blocks = std::move(next_blocks);
@ -3182,6 +3234,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetInt(m_ignore_fractional_outputs ? 1 : 0); value2.SetInt(m_ignore_fractional_outputs ? 1 : 0);
json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator()); json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator());
value2.SetInt(m_track_uses ? 1 : 0);
json.AddMember("track_uses", value2, json.GetAllocator());
value2.SetUint(m_subaddress_lookahead_major); value2.SetUint(m_subaddress_lookahead_major);
json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator()); json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator());
@ -3328,6 +3383,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_key_reuse_mitigation2 = true; m_key_reuse_mitigation2 = true;
m_segregation_height = 0; m_segregation_height = 0;
m_ignore_fractional_outputs = true; m_ignore_fractional_outputs = true;
m_track_uses = false;
m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR; m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR;
m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR; m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR;
m_original_keys_available = false; m_original_keys_available = false;
@ -3480,6 +3536,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_segregation_height = field_segregation_height; m_segregation_height = field_segregation_height;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true); GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true);
m_ignore_fractional_outputs = field_ignore_fractional_outputs; m_ignore_fractional_outputs = field_ignore_fractional_outputs;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, track_uses, int, Int, false, false);
m_track_uses = field_track_uses;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR); GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR);
m_subaddress_lookahead_major = field_subaddress_lookahead_major; m_subaddress_lookahead_major = field_subaddress_lookahead_major;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR); GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR);
@ -5266,6 +5324,10 @@ void wallet2::rescan_blockchain(bool hard, bool refresh)
m_transfers.clear(); m_transfers.clear();
m_key_images.clear(); m_key_images.clear();
m_pub_keys.clear(); m_pub_keys.clear();
m_unconfirmed_txs.clear();
m_payments.clear();
m_confirmed_txs.clear();
m_unconfirmed_payments.clear();
m_scanned_pool_txs[0].clear(); m_scanned_pool_txs[0].clear();
m_scanned_pool_txs[1].clear(); m_scanned_pool_txs[1].clear();

@ -273,6 +273,7 @@ namespace tools
bool m_key_image_partial; bool m_key_image_partial;
std::vector<rct::key> m_multisig_k; std::vector<rct::key> m_multisig_k;
std::vector<multisig_info> m_multisig_info; // one per other participant std::vector<multisig_info> m_multisig_info; // one per other participant
std::vector<std::pair<uint64_t, crypto::hash>> m_uses;
bool is_rct() const { return m_rct; } bool is_rct() const { return m_rct; }
uint64_t amount() const { return m_amount; } uint64_t amount() const { return m_amount; }
@ -297,6 +298,7 @@ namespace tools
FIELD(m_key_image_partial) FIELD(m_key_image_partial)
FIELD(m_multisig_k) FIELD(m_multisig_k)
FIELD(m_multisig_info) FIELD(m_multisig_info)
FIELD(m_uses)
END_SERIALIZE() END_SERIALIZE()
}; };
@ -984,6 +986,8 @@ namespace tools
void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; } void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; }
bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; } bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; }
void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; } void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; }
bool track_uses() const { return m_track_uses; }
void track_uses(bool value) { m_track_uses = value; }
const std::string & device_name() const { return m_device_name; } const std::string & device_name() const { return m_device_name; }
void device_name(const std::string & device_name) { m_device_name = device_name; } void device_name(const std::string & device_name) { m_device_name = device_name; }
const std::string & device_derivation_path() const { return m_device_derivation_path; } const std::string & device_derivation_path() const { return m_device_derivation_path; }
@ -1249,8 +1253,8 @@ namespace tools
* \param password Password of wallet file * \param password Password of wallet file
*/ */
bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password); bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password);
void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data); void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector<uint64_t> &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen, const tx_cache_data &tx_cache_data, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset); void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const parsed_block &parsed_block, const crypto::hash& bl_id, uint64_t height, const std::vector<tx_cache_data> &tx_cache_data, size_t tx_cache_data_offset, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
void detach_blockchain(uint64_t height); void detach_blockchain(uint64_t height);
void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const; void get_short_chain_history(std::list<crypto::hash>& ids, uint64_t granularity = 1) const;
bool clear(); bool clear();
@ -1258,7 +1262,7 @@ namespace tools
void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes); void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes);
void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false); void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false);
void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error); void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error);
void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added); void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added, std::map<std::pair<uint64_t, uint64_t>, size_t> *output_tracker_cache = NULL);
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers) const; uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers) const;
bool prepare_file_names(const std::string& file_path); bool prepare_file_names(const std::string& file_path);
void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height); void process_unconfirmed(const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t height);
@ -1312,6 +1316,7 @@ namespace tools
std::unordered_set<crypto::public_key> &pkeys) const; std::unordered_set<crypto::public_key> &pkeys) const;
void cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const; void cache_tx_data(const cryptonote::transaction& tx, const crypto::hash &txid, tx_cache_data &tx_cache_data) const;
std::shared_ptr<std::map<std::pair<uint64_t, uint64_t>, size_t>> create_output_tracker_cache() const;
void setup_new_blockchain(); void setup_new_blockchain();
void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file); void create_keys_file(const std::string &wallet_, bool watch_only, const epee::wipeable_string &password, bool create_address_file);
@ -1395,6 +1400,7 @@ namespace tools
bool m_key_reuse_mitigation2; bool m_key_reuse_mitigation2;
uint64_t m_segregation_height; uint64_t m_segregation_height;
bool m_ignore_fractional_outputs; bool m_ignore_fractional_outputs;
bool m_track_uses;
bool m_is_initialized; bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy; NodeRPCProxy m_node_rpc_proxy;
std::unordered_set<crypto::hash> m_scanned_pool_txs[2]; std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
@ -1444,7 +1450,7 @@ namespace tools
}; };
} }
BOOST_CLASS_VERSION(tools::wallet2, 27) BOOST_CLASS_VERSION(tools::wallet2, 27)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 10) BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1) BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0) BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1) BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
@ -1593,6 +1599,9 @@ namespace boost
return; return;
} }
a & x.m_key_image_requested; a & x.m_key_image_requested;
if (ver < 11)
return;
a & x.m_uses;
} }
template <class Archive> template <class Archive>

@ -69,11 +69,22 @@ TEST(notify, works)
tools::Notify notify(spec.c_str()); tools::Notify notify(spec.c_str());
notify.notify("1111111111111111111111111111111111111111111111111111111111111111"); notify.notify("1111111111111111111111111111111111111111111111111111111111111111");
epee::misc_utils::sleep_no_w(100); bool ok = false;
for (int i = 0; i < 10; ++i)
std::string s; {
ASSERT_TRUE(epee::file_io_utils::load_file_to_string(name_template, s)); epee::misc_utils::sleep_no_w(100);
ASSERT_TRUE(s == "1111111111111111111111111111111111111111111111111111111111111111");
std::string s;
if (epee::file_io_utils::load_file_to_string(name_template, s))
{
if (s == "1111111111111111111111111111111111111111111111111111111111111111")
{
ok = true;
break;
}
std::cout << "got: [" << s << "]" << std::endl;
}
}
boost::filesystem::remove(name_template); boost::filesystem::remove(name_template);
ASSERT_TRUE(ok);
} }

@ -42,7 +42,7 @@ TEST(peer_list, peer_list_general)
#define ADD_GRAY_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple; ple.last_seen=last_seen_;ple.adr = addr_; ple.id = id_;plm.append_with_peer_gray(ple);} #define ADD_GRAY_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple; ple.last_seen=last_seen_;ple.adr = addr_; ple.id = id_;plm.append_with_peer_gray(ple);}
#define ADD_WHITE_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple;ple.last_seen=last_seen_; ple.adr = addr_; ple.id = id_;plm.append_with_peer_white(ple);} #define ADD_WHITE_NODE(addr_, id_, last_seen_) { nodetool::peerlist_entry ple;ple.last_seen=last_seen_; ple.adr = addr_; ple.id = id_;plm.append_with_peer_white(ple);}
#define PRINT_HEAD(step) {std::list<nodetool::peerlist_entry> bs_head; bool r = plm.get_peerlist_head(bs_head, 100);std::cout << "step " << step << ": " << bs_head.size() << std::endl;} #define PRINT_HEAD(step) {std::vector<nodetool::peerlist_entry> bs_head; bool r = plm.get_peerlist_head(bs_head, 100);std::cout << "step " << step << ": " << bs_head.size() << std::endl;}
ADD_GRAY_NODE(MAKE_IPV4_ADDRESS(123,43,12,1, 8080), 121241, 34345); ADD_GRAY_NODE(MAKE_IPV4_ADDRESS(123,43,12,1, 8080), 121241, 34345);
ADD_GRAY_NODE(MAKE_IPV4_ADDRESS(123,43,12,2, 8080), 121241, 34345); ADD_GRAY_NODE(MAKE_IPV4_ADDRESS(123,43,12,2, 8080), 121241, 34345);
@ -58,7 +58,7 @@ TEST(peer_list, peer_list_general)
size_t gray_list_size = plm.get_gray_peers_count(); size_t gray_list_size = plm.get_gray_peers_count();
ASSERT_EQ(gray_list_size, 1); ASSERT_EQ(gray_list_size, 1);
std::list<nodetool::peerlist_entry> bs_head; std::vector<nodetool::peerlist_entry> bs_head;
bool r = plm.get_peerlist_head(bs_head, 100); bool r = plm.get_peerlist_head(bs_head, 100);
std::cout << bs_head.size() << std::endl; std::cout << bs_head.size() << std::endl;
ASSERT_TRUE(r); ASSERT_TRUE(r);
@ -78,7 +78,7 @@ TEST(peer_list, merge_peer_lists)
//ADD_NODE_TO_PL("\2", \3, 0x\1, (1353346618 -(\4*60*60*24+\5*60*60+\6*60+\7 )));\n //ADD_NODE_TO_PL("\2", \3, 0x\1, (1353346618 -(\4*60*60*24+\5*60*60+\6*60+\7 )));\n
nodetool::peerlist_manager plm; nodetool::peerlist_manager plm;
plm.init(false); plm.init(false);
std::list<nodetool::peerlist_entry> outer_bs; std::vector<nodetool::peerlist_entry> outer_bs;
#define ADD_NODE_TO_PL(ip_, port_, id_, timestamp_) { nodetool::peerlist_entry ple; epee::string_tools::get_ip_int32_from_string(ple.adr.ip, ip_); ple.last_seen = timestamp_; ple.adr.port = port_; ple.id = id_;outer_bs.push_back(ple);} #define ADD_NODE_TO_PL(ip_, port_, id_, timestamp_) { nodetool::peerlist_entry ple; epee::string_tools::get_ip_int32_from_string(ple.adr.ip, ip_); ple.last_seen = timestamp_; ple.adr.port = port_; ple.id = id_;outer_bs.push_back(ple);}

@ -89,11 +89,11 @@ public:
virtual uint64_t get_tx_block_height(const crypto::hash& h) const { return 0; } 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_num_outputs(const uint64_t& amount) const { return 1; }
virtual uint64_t get_indexing_base() const { return 0; } 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) { return cryptonote::output_data_t(); } virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) 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_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 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 {} 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 {}
virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) {} virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) const {}
virtual bool can_thread_bulk_indices() const { return false; } virtual bool can_thread_bulk_indices() const { return false; }
virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const { return std::vector<uint64_t>(); } virtual std::vector<uint64_t> get_tx_output_indices(const crypto::hash& h) const { return std::vector<uint64_t>(); }
virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector<uint64_t>(); } virtual std::vector<uint64_t> get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector<uint64_t>(); }

@ -13,18 +13,18 @@ p7gDvxXOGxzq0sqfPTWTBdCj1OPfunHbbeH8ypwBlNpwVG40fJdya+Dqjwu25qX6
Xh5vxLzeJTBmlawa97MCliPvzzJgW9qHRVCa9lLloGVYLiUOS0N+dZ/r/QARAQAB Xh5vxLzeJTBmlawa97MCliPvzzJgW9qHRVCa9lLloGVYLiUOS0N+dZ/r/QARAQAB
tD5tb25lcm9tb29vLW1vbmVybyA8bW9uZXJvbW9vby1tb25lcm9AdXNlcnMubm9y tD5tb25lcm9tb29vLW1vbmVybyA8bW9uZXJvbW9vby1tb25lcm9AdXNlcnMubm9y
ZXBseS5naXRodWIuY29tPokCPwQTAQIAKQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMB ZXBseS5naXRodWIuY29tPokCPwQTAQIAKQIbAwcLCQgHAwIBBhUIAgkKCwQWAgMB
Ah4BAheABQJbof8TBQkLMcqRAAoJEGhvB0VNbO/DOrcP/1eG3gkIgq+lXKlv/lta Ah4BAheABQJcEB4SBQkLn+mRAAoJEGhvB0VNbO/DzSIQALXk6ST5Uoxh5+NLBJgI
ZFl8jS5iQUwxTHv8s+O7pbL2mwKt5oM8QmXVMFLlaanENmH0y/DhWRYIYuKTifDN GR2NOCFwsU+97VOkZWZnzpk+JdUrq/I9JmWWTegGKu3it5YvM8xY1zD1l+RXlnmY
tXOxENCZhxgjlVxAtnMdD2J8MJANzV2MYGLbGQeFAuZHIL2LMfvUENLYx/jJpe7f Bg7oT6N63lL8hBhxGm9Hk2A1VJlEjtgtvjbg5yLSdvjxJL1vrmchWGwFWoHT9uIh
93kXZoQio7rIolnlbM1QoJLxi/7HlOt/VsopJlV2wAmOmlpyWDnOZtUtZgiCGV6a oefemb3TQ1U+ADVsW42jXca650/rqvsUMpmQbDfHxUBIfpbxgTWz8sHuMfhFB3R0
apFzTs2m3n2GP7+8PG/W01/jVyFqixGW8cWVZORBMhjro2JqrRvw7U+Ypk2o7Em4 nzSuZ1E1Pbg5jWYxd6sXpb1VFZ7TaQNVGB+4wMe8AH8/0qziLVTXvSkoer6qxU+r
SAnAJyzqpTDh9zf0QWkQXN83YThB3dk1M1FXOyKtZ8G+YVNfs5Ldr7tHNbqKi2v8 e9M9/Rgue1FJSzZogUekIqyNLsvAeATSCYzi8NoywkUbAq6AqazJtdcOD+7M2/Vl
lPaPIDQ7UmxZhy9vraKss0/3AEXaiE2eSvLc4eCcLiS4yVQ2KJpK5TUvz3cP1D5C pdQEnIKSO/9xrziUQifRsPx4LOjf2d2Hvor/rBJYwoI1cFgR5pmH30Mi7OY0mMmm
USsjxUZvolUELBtNaRVAsxX6OAyA8FjwJ8AKCqyR0NHvrbYhj54N1Js8PWtb+qqk 2TMUPPz7YiVY+RPPpY3Mg5oPRe6sHVAdFYBmc0PTR4v92iYgfQXzoCd5HOJI9QB3
5sBLKOwEPaWM1uG6SJabrY1xu2VNLOGdJA9bRfyyzfpXksD0lFgwLKki6ReqqoMS SwrKz7cNLQwob2za1AXZ3sUp+yok6QMt8Tk6xIbMAjeR4jVeP8iQHhiVS1zx5z/g
QiVdymhcp55J4tFwsDkzJX7296d1x3r7GAIQMLNc7YizukWfNtvUkSUsAwp+RKUx lCAfb0hJnykoANgIZvJR/L+tuZjVStqnXjHgreY3IjlWTaNjZ/X5uMvd6zivqI9a
TTwkwL1ztzSRpt3hGMJ9SfULTaQD7YAYfz4kitMBNpm90CLFa4CeINu98gE9Ogmc aEmqw/ZDCXRMAtjUCpUvpNlqAgqqbQsx6MFDnMbd4BuKQONeAFLm/Rp31nIvt1vb
R+CGQOHLUC3rXubgRCiQg5wfuQINBFQym34BEADHtTHduZFdu76RAzqTjT94F92L +Iu3vkXBbbjb5yMu/dcpgSRUuQINBFQym34BEADHtTHduZFdu76RAzqTjT94F92L
xSSopLSk7/sdLWTc2ERmjDId7dKmqrL1Kh2kqAtHY3Rq8Y839LGmbJCzI1kJyOHF xSSopLSk7/sdLWTc2ERmjDId7dKmqrL1Kh2kqAtHY3Rq8Y839LGmbJCzI1kJyOHF
o9jkEI93sqXcztLjizPVukqClOZNt3NV/nvefH6JSdqWcnC4V1mQr2Ztl0j+51i+ o9jkEI93sqXcztLjizPVukqClOZNt3NV/nvefH6JSdqWcnC4V1mQr2Ztl0j+51i+
NYVwGjlsOMlBER+LW/s7egRqAQonrcEB5vsSAzd8mOlNKjRAnDCV+C21GDKxzb80 NYVwGjlsOMlBER+LW/s7egRqAQonrcEB5vsSAzd8mOlNKjRAnDCV+C21GDKxzb80
@ -35,17 +35,17 @@ xRFfhoiiPyjjPRmJ+/iG3KXLzEiMfbyTFzGkX3Z9BJTxemUx8JOSVQXa++t4w39J
UwzwBKNItDhtQqJpCaF43fJ4ykLMJi5gRpgqtb+T3CF0abXNII1IfS8a0fSpd48d UwzwBKNItDhtQqJpCaF43fJ4ykLMJi5gRpgqtb+T3CF0abXNII1IfS8a0fSpd48d
6hzoCVqpvWsI1fOY5Ui0BIgubNhkr4OJDCWBT5zhxjCJ3QiUSKyyqjfw1Fpuf/0Y 6hzoCVqpvWsI1fOY5Ui0BIgubNhkr4OJDCWBT5zhxjCJ3QiUSKyyqjfw1Fpuf/0Y
CSA9Q9FSCq9qTppJs5ITHVjhWw2zxrJEG+P2+dvryBhV9l4T2xx1oHqlKX8zzLBG CSA9Q9FSCq9qTppJs5ITHVjhWw2zxrJEG+P2+dvryBhV9l4T2xx1oHqlKX8zzLBG
kS8NmnxoRFQs5rZYvQARAQABiQIlBBgBAgAPAhsMBQJX3tl5BQkHbqT4AAoJEGhv kS8NmnxoRFQs5rZYvQARAQABiQIlBBgBAgAPAhsMBQJcEB4eBQkLn+meAAoJEGhv
B0VNbO/DrN4QAJVTg2l91LSxb2dTikXbkRCPev1Eiqjd3d4TZIyE7yeYreHUyfcz B0VNbO/DjzYP/2A6HtpvPkD+s/0+Ghmp5Rw7HIvZz0RnCsvM3qVQqVn3JTqHXyhD
sytEsMUpd5nqqL/QMOwgC8Dm+77Yp480atI/c0wQh30EfJq1YP4q/gwv8EtriFo6 5GmZrCxhliW1nRBITaKSRHXSGeE/O1BtK6eW/Z1P6bWJVd+R9vhaZlLU2sswiFzu
ZaqYNzajmB8otz6yyb5RD9S6ocZX5b22nnNM/ihiTQJiqJKC2XHPQH3/grniU9if q3s7bL/Fo9VRc0SX6j6JDh1FZ3JcebUfY59sixHLqZuAk9m97z6H1NjS+f4pB5Tp
WXUlY7Fo+8lRn/aRPMjYT2elsugru8GoplDMyfPRymnMJmTwNPYkg0Dnm2JUXYhH n1nnRgdvYk4tjlk4mmluIAwjq8Ll6gw6ntwjX9Gq9OblutTr2MZDyTIOxcG54ZN2
VLO6Ebh7fUChsiGNmSp+siv7fcZIf20+LvoymgyT+49LrrQMvRleOqaJc1LBKaK6 2t5JA7Syh0He6dn/NLlb//bPPnic3GuYfkgKht8M1XCJfnDKju+I9qRGf1DYIjP7
1yU+jLk1f9bFCMORQoTxvIVaSnjMWAeKDxi8nwuVfUJpQYXmbOOqMZgoFi6t+U7/ m24IDC0MM9Fo7KIUY+vcV0J/BIkkZtZ9xh0iEEnR/KqYXmClym+EiWCwPhLloKL3
T6Cz1CGKv3JgEveWyHeOvsjopej3a4Hmk7QGM/xJrd83roUjypjx5lTeMDvcPlPs 6cZr5MaiYJsodYa73x35pSGvioUrBDb78v8nCNhoTUXzZv8E0s/0YI2UZSGhVEC6
IQOy33qWguR1xoEnwAp9ov/meS7HtUOoC0m9ROZqWT6ArN+1ONplFP4GTsuW91Qz ANNXPvKeOdibGNDM4JOwETabkEng38UE6Oa7Qonra2MWsPegh+mnZ7/sqrktQRMB
pacQMl09F0KF1MacAdpauCOKj+wy9XPUW8v3kWZufUSgNtOLHS+kVumkqdJuJ0aB T/Xne6vapDONeLeY2hVcT0j9f/S8rgpHPjP4/hmYE9d38Euwa7TZ0lHWcmJzQy6F
7Ezc1yYY6DwRFOdlUpTJkRMozyPRvS15Lz/vPEhcbxMHRAg611CS2CqTEIbk2chJ 7HfGR3oYAYAwRnvl+kYUGZ46u9Nodi4+wycFc4+IpwFtnlUzRBOcOilnR2X6KFJW
QBlj77a45lDTXGQHFVYXlbXx/HWb5zOGpNji0QhY1hOABRo78DT5yda+ SiVss1i7ECcWaKCBNN1MrpwGWeuSbCQ00c3bxe6ZN6goB1t2u1KAZqMK
=ksQj =HFHX
-----END PGP PUBLIC KEY BLOCK----- -----END PGP PUBLIC KEY BLOCK-----

Loading…
Cancel
Save