aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt100
-rw-r--r--README.md38
-rw-r--r--cmake/CheckLinkerFlag.c14
-rw-r--r--cmake/CheckLinkerFlag.cmake47
-rw-r--r--cmake/FindReadline.cmake55
-rw-r--r--contrib/epee/include/memwipe.h (renamed from src/common/memwipe.h)0
-rw-r--r--contrib/epee/include/net/http_auth.h7
-rw-r--r--contrib/epee/include/net/http_protocol_handler.h3
-rw-r--r--contrib/epee/include/net/http_server_impl_base.h3
-rw-r--r--contrib/epee/include/net/network_throttle.hpp3
-rw-r--r--contrib/epee/include/serialization/keyvalue_serialization.h1
-rw-r--r--contrib/epee/include/storages/levin_abstract_invoke2.h26
-rw-r--r--contrib/epee/include/storages/portable_storage_val_converters.h6
-rw-r--r--contrib/epee/src/CMakeLists.txt9
-rw-r--r--contrib/epee/src/connection_basic.cpp1
-rw-r--r--contrib/epee/src/http_auth.cpp7
-rw-r--r--contrib/epee/src/memwipe.c (renamed from src/common/memwipe.c)0
-rw-r--r--contrib/epee/src/wipeable_string.cpp2
-rw-r--r--external/db_drivers/liblmdb/CMakeLists.txt1
-rw-r--r--external/easylogging++/CMakeLists.txt1
-rw-r--r--external/easylogging++/ea_config.h2
-rw-r--r--external/miniupnpc/CMakeLists.txt7
-rw-r--r--external/unbound/CMakeLists.txt1
-rw-r--r--src/blockchain_db/blockchain_db.h5
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp70
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h2
-rw-r--r--src/blockchain_utilities/CMakeLists.txt4
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp4
-rw-r--r--src/blocks/CMakeLists.txt4
-rw-r--r--src/common/CMakeLists.txt9
-rw-r--r--src/common/apply_permutation.h2
-rw-r--r--src/common/i18n.cpp43
-rw-r--r--src/common/password.cpp2
-rw-r--r--src/common/threadpool.cpp8
-rw-r--r--src/common/util.cpp1
-rw-r--r--src/crypto/CMakeLists.txt1
-rw-r--r--src/crypto/blake256.c2
-rw-r--r--src/crypto/chacha.h2
-rw-r--r--src/crypto/crypto.h2
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h1
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.cpp2
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp1
-rw-r--r--src/cryptonote_core/blockchain.cpp6
-rw-r--r--src/cryptonote_core/blockchain.h2
-rw-r--r--src/cryptonote_core/tx_pool.cpp39
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl7
-rw-r--r--src/daemon/CMakeLists.txt6
-rw-r--r--src/daemon/main.cpp2
-rw-r--r--src/gen_multisig/CMakeLists.txt2
-rw-r--r--src/mnemonics/CMakeLists.txt1
-rw-r--r--src/mnemonics/electrum-words.cpp2
-rw-r--r--src/p2p/CMakeLists.txt1
-rw-r--r--src/ringct/rctTypes.h2
-rw-r--r--src/rpc/CMakeLists.txt2
-rw-r--r--src/rpc/core_rpc_server.cpp3
-rw-r--r--src/rpc/zmq_server.cpp2
-rw-r--r--src/serialization/container.h113
-rw-r--r--src/serialization/deque.h64
-rw-r--r--src/serialization/list.h72
-rw-r--r--src/serialization/serialization.h16
-rw-r--r--src/serialization/set.h85
-rw-r--r--src/serialization/unordered_set.h58
-rw-r--r--src/serialization/vector.h82
-rw-r--r--src/simplewallet/CMakeLists.txt2
-rw-r--r--src/simplewallet/simplewallet.cpp332
-rw-r--r--src/simplewallet/simplewallet.h5
-rw-r--r--src/wallet/api/wallet.cpp49
-rw-r--r--src/wallet/api/wallet.h2
-rw-r--r--src/wallet/api/wallet2_api.h6
-rw-r--r--src/wallet/wallet2.cpp476
-rw-r--r--src/wallet/wallet2.h52
-rw-r--r--src/wallet/wallet_errors.h11
-rw-r--r--src/wallet/wallet_rpc_server.cpp473
-rw-r--r--src/wallet/wallet_rpc_server.h9
-rw-r--r--src/wallet/wallet_rpc_server_commands_defs.h70
-rw-r--r--tests/fuzz/cold-outputs.cpp10
-rw-r--r--tests/fuzz/cold-transaction.cpp10
-rw-r--r--tests/fuzz/signature.cpp10
-rw-r--r--tests/gtest/cmake/internal_utils.cmake2
-rw-r--r--tests/performance_tests/CMakeLists.txt2
-rw-r--r--tests/performance_tests/main.cpp3
-rw-r--r--tests/performance_tests/subaddress_expand.h65
-rw-r--r--tests/unit_tests/crypto.cpp24
-rw-r--r--tests/unit_tests/hardfork.cpp2
-rw-r--r--tests/unit_tests/http.cpp22
-rw-r--r--tests/unit_tests/memwipe.cpp2
-rw-r--r--tests/unit_tests/serialization.cpp1
-rw-r--r--tests/unit_tests/subaddress.cpp17
-rw-r--r--tests/unit_tests/varint.cpp1
-rw-r--r--translations/CMakeLists.txt63
-rw-r--r--translations/generate_translations_header.c86
-rw-r--r--translations/monero_sv.ts2783
-rw-r--r--utils/build_scripts/android32.Dockerfile2
-rw-r--r--utils/build_scripts/android64.Dockerfile2
94 files changed, 4824 insertions, 836 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 11c549d7c..a0508adfd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -27,6 +27,13 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+list(INSERT CMAKE_MODULE_PATH 0
+ "${CMAKE_SOURCE_DIR}/cmake")
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+include(CheckLinkerFlag)
+include(CheckLibraryExists)
+
if (IOS)
INCLUDE(CmakeLists_IOS.txt)
endif()
@@ -48,6 +55,31 @@ function (die msg)
message(FATAL_ERROR "${BoldRed}${msg}${ColourReset}")
endfunction ()
+function (add_c_flag_if_supported flag var)
+ string(REPLACE "-" "_" supported ${flag}_c)
+ check_c_compiler_flag(${flag} ${supported})
+ if(${${supported}})
+ set(${var} "${${var}} ${flag}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function (add_cxx_flag_if_supported flag var)
+ string(REPLACE "-" "_" supported ${flag}_cxx)
+ check_cxx_compiler_flag(${flag} ${supported})
+ if(${${supported}})
+ set(${var} "${${var}} ${flag}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+function (add_linker_flag_if_supported flag var)
+ string(REPLACE "-" "_" supported ${flag}_ld)
+ string(REPLACE "," "_" supported ${flag}_ld)
+ check_linker_flag(${flag} ${supported})
+ if(${${supported}})
+ set(${var} "${${var}} ${flag}" PARENT_SCOPE)
+ endif()
+endfunction()
+
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
message(STATUS "Setting default build type: ${CMAKE_BUILD_TYPE}")
@@ -210,11 +242,11 @@ endif()
if (BUILD_SHARED_LIBS)
message(STATUS "Building internal libraries with position independent code")
- set(PIC_FLAG "-fPIC")
add_definitions("-DBUILD_SHARED_LIBS")
else()
message(STATUS "Building internal libraries as static")
endif()
+set(PIC_FLAG "-fPIC")
if(MINGW)
string(REGEX MATCH "^[^/]:/[^/]*" msys2_install_path "${CMAKE_C_COMPILER}")
@@ -365,6 +397,14 @@ endif()
add_definitions(-DAUTO_INITIALIZE_EASYLOGGINGPP)
+# Generate header for embedded translations
+include(ExternalProject)
+ExternalProject_Add(generate_translations_header
+ SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/translations"
+ BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/translations"
+ INSTALL_COMMAND cmake -E echo "")
+include_directories("${CMAKE_CURRENT_BINARY_DIR}/translations")
+
add_subdirectory(external)
# Final setup for miniupnpc
@@ -470,6 +510,52 @@ else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-strict-aliasing")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
+ # if those don't work for your compiler, single it out where appropriate
+ if(CMAKE_BUILD_TYPE STREQUAL "Release")
+ set(C_SECURITY_FLAGS "${C_SECURITY_FLAGS} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1")
+ set(CXX_SECURITY_FLAGS "${CXX_SECURITY_FLAGS} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1")
+ endif()
+
+ # warnings
+ add_c_flag_if_supported(-Wformat C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-Wformat CXX_SECURITY_FLAGS)
+ add_c_flag_if_supported(-Wformat-security C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-Wformat-security CXX_SECURITY_FLAGS)
+
+ # -fstack-protector
+ add_c_flag_if_supported(-fstack-protector C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-fstack-protector CXX_SECURITY_FLAGS)
+ add_c_flag_if_supported(-fstack-protector-strong C_SECURITY_FLAGS)
+ add_cxx_flag_if_supported(-fstack-protector-strong CXX_SECURITY_FLAGS)
+
+ # linker
+ if (NOT WIN32)
+ # Windows binaries die on startup with PIE
+ add_linker_flag_if_supported(-pie LD_SECURITY_FLAGS)
+ endif()
+ add_linker_flag_if_supported(-Wl,-z,relro LD_SECURITY_FLAGS)
+ add_linker_flag_if_supported(-Wl,-z,now LD_SECURITY_FLAGS)
+ add_linker_flag_if_supported(-Wl,-z,noexecstack noexecstack_SUPPORTED)
+ if (noexecstack_SUPPORTED)
+ set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecstack")
+ set(LD_RAW_FLAGS ${LD_RAW_FLAGS} -z noexecstack)
+ endif()
+ add_linker_flag_if_supported(-Wl,-z,noexecheap noexecheap_SUPPORTED)
+ if (noexecheap_SUPPORTED)
+ set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap")
+ set(LD_RAW_FLAGS ${LD_RAW_FLAGS} -z noexecheap)
+ endif()
+
+ # some windows linker bits
+ if (WIN32)
+ add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS)
+ add_linker_flag_if_supported(-Wl,--nxcompat LD_SECURITY_FLAGS)
+ endif()
+
+ message(STATUS "Using C security hardening flags: ${C_SECURITY_FLAGS}")
+ message(STATUS "Using C++ security hardening flags: ${CXX_SECURITY_FLAGS}")
+ message(STATUS "Using linker security hardening flags: ${LD_SECURITY_FLAGS}")
+
option(NO_AES "Explicitly disable AES support" ${NO_AES})
if(NO_AES)
@@ -498,8 +584,9 @@ else()
message(STATUS "AES support disabled")
endif()
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_CPP_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG}")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG} ${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} ${ARCH_FLAG} ${COVERAGE_FLAGS} ${PIC_FLAG} ${CXX_SECURITY_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS}")
# 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.
@@ -586,6 +673,7 @@ else()
if(ANDROID AND NOT BUILD_GUI_DEPS STREQUAL "ON" OR IOS)
#From Android 5: "only position independent executables (PIE) are supported"
message(STATUS "Enabling PIE executable")
+ set(PIC_FLAG "")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIE")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -fPIE -pie")
@@ -672,7 +760,7 @@ if(NOT Boost_FOUND)
die("Could not find Boost libraries, please make sure you have installed Boost or libboost-all-dev (1.58) or the equivalent")
elseif(Boost_FOUND)
message(STATUS "Found Boost Version: ${Boost_VERSION}")
- if (Boost_VERSION VERSION_LESS 1.62 AND NOT (OPENSSL_VERSION VERSION_LESS 1.1))
+ if (Boost_VERSION VERSION_LESS 106200 AND NOT (OPENSSL_VERSION VERSION_LESS 1.1))
message(FATAL_ERROR "Boost older than 1.62 is too old to link with OpenSSL 1.1 or newer. "
"Update Boost or install OpenSSL 1.0 and set path to it when running cmake: "
"cmake -DOPENSSL_ROOT_DIR='/usr/include/openssl-1.0;/usr/lib/openssl-1.0'")
@@ -778,11 +866,11 @@ option(BUILD_GUI_DEPS "Build GUI dependencies." OFF)
option(INSTALL_VENDORED_LIBUNBOUND "Install libunbound binary built from source vendored with this repo." OFF)
-include(CheckCCompilerFlag)
-
CHECK_C_COMPILER_FLAG(-std=c11 HAVE_C11)
include(CheckLibraryExists)
+include(CheckFunctionExists)
check_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
check_library_exists(c explicit_bzero "strings.h" HAVE_EXPLICIT_BZERO)
+check_function_exists(strptime HAVE_STRPTIME)
diff --git a/README.md b/README.md
index 0de529fe3..105500289 100644
--- a/README.md
+++ b/README.md
@@ -163,25 +163,25 @@ sources are also used for statically-linked builds because distribution
packages often include only shared library binaries (`.so`) but not static
library archives (`.a`).
-| Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Optional | Purpose |
-| -------------- | ------------- | ---------| ------------------ | -------------- | -------- | -------------- |
-| GCC | 4.7.3 | NO | `build-essential` | `base-devel` | NO | |
-| CMake | 3.0.0 | NO | `cmake` | `cmake` | NO | |
-| pkg-config | any | NO | `pkg-config` | `base-devel` | NO | |
-| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | NO | C++ libraries |
-| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | NO | sha256 sum |
-| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | NO | ZeroMQ library |
-| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | NO | DNS resolver |
-| libsodium | ? | NO | `libsodium-dev` | ? | NO | libsodium |
-| libminiupnpc | 2.0 | YES | `libminiupnpc-dev` | `miniupnpc` | YES | NAT punching |
-| libunwind | any | NO | `libunwind8-dev` | `libunwind` | YES | Stack traces |
-| liblzma | any | NO | `liblzma-dev` | `xz` | YES | For libunwind |
-| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | YES | Input editing |
-| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | YES | SSL toolkit |
-| expat | 1.1 | NO | `libexpat1-dev` | `expat` | YES | XML parsing |
-| GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | YES | Test suite |
-| Doxygen | any | NO | `doxygen` | `doxygen` | YES | Documentation |
-| Graphviz | any | NO | `graphviz` | `graphviz` | YES | Documentation |
+| Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Fedora | Optional | Purpose |
+| ------------ | ------------- | -------- | ------------------ | ------------ | ----------------- | -------- | -------------- |
+| GCC | 4.7.3 | NO | `build-essential` | `base-devel` | `gcc` | NO | |
+| CMake | 3.0.0 | NO | `cmake` | `cmake` | `cmake` | NO | |
+| pkg-config | any | NO | `pkg-config` | `base-devel` | `pkgconf` | NO | |
+| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | `boost-devel` | NO | C++ libraries |
+| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `openssl-devel` | NO | sha256 sum |
+| libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | `cppzmq-devel` | NO | ZeroMQ library |
+| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | NO | DNS resolver |
+| libsodium | ? | NO | `libsodium-dev` | ? | `libsodium-devel` | NO | libsodium |
+| libminiupnpc | 2.0 | YES | `libminiupnpc-dev` | `miniupnpc` | `miniupnpc-devel` | YES | NAT punching |
+| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | YES | Stack traces |
+| liblzma | any | NO | `liblzma-dev` | `xz` | `xz-devel` | YES | For libunwind |
+| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | YES | Input editing |
+| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | `ldns-devel` | YES | SSL toolkit |
+| expat | 1.1 | NO | `libexpat1-dev` | `expat` | `expat-devel` | YES | XML parsing |
+| GTest | 1.5 | YES | `libgtest-dev`^ | `gtest` | `gtest-devel` | YES | Test suite |
+| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | YES | Documentation |
+| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | YES | Documentation |
[^] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
diff --git a/cmake/CheckLinkerFlag.c b/cmake/CheckLinkerFlag.c
new file mode 100644
index 000000000..a0dcc168d
--- /dev/null
+++ b/cmake/CheckLinkerFlag.c
@@ -0,0 +1,14 @@
+#ifdef __CLASSIC_C__
+int main()
+{
+ int ac;
+ char* av[];
+#else
+int main(int ac, char* av[])
+{
+#endif
+ if (ac > 1000) {
+ return *av[0];
+ }
+ return 0;
+}
diff --git a/cmake/CheckLinkerFlag.cmake b/cmake/CheckLinkerFlag.cmake
new file mode 100644
index 000000000..a3879d0be
--- /dev/null
+++ b/cmake/CheckLinkerFlag.cmake
@@ -0,0 +1,47 @@
+include(CheckCCompilerFlag)
+
+macro(CHECK_LINKER_FLAG flag VARIABLE)
+ if(NOT DEFINED "${VARIABLE}")
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(STATUS "Looking for ${flag} linker flag")
+ endif()
+
+ set(_cle_source ${CMAKE_SOURCE_DIR}/cmake/CheckLinkerFlag.c)
+
+ set(saved_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
+ set(CMAKE_C_FLAGS "${flag}")
+ try_compile(${VARIABLE}
+ ${CMAKE_BINARY_DIR}
+ ${_cle_source}
+ COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${flag}
+ CMAKE_FLAGS
+ OUTPUT_VARIABLE OUTPUT)
+ unset(_cle_source)
+ set(CMAKE_C_FLAGS ${saved_CMAKE_C_FLAGS})
+ unset(saved_CMAKE_C_FLAGS)
+
+ if ("${OUTPUT}" MATCHES "warning.*ignored")
+ set(${VARIABLE} 0)
+ endif()
+
+ if(${VARIABLE})
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(STATUS "Looking for ${flag} linker flag - found")
+ endif()
+ set(${VARIABLE} 1 CACHE INTERNAL "Have linker flag ${flag}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Determining if the ${flag} linker flag is supported "
+ "passed with the following output:\n"
+ "${OUTPUT}\n\n")
+ else()
+ if(NOT CMAKE_REQUIRED_QUIET)
+ message(STATUS "Looking for ${flag} linker flag - not found")
+ endif()
+ set(${VARIABLE} "" CACHE INTERNAL "Have linker flag ${flag}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Determining if the ${flag} linker flag is suppored "
+ "failed with the following output:\n"
+ "${OUTPUT}\n\n")
+ endif()
+ endif()
+endmacro()
diff --git a/cmake/FindReadline.cmake b/cmake/FindReadline.cmake
index cdce0bfca..87f8ccace 100644
--- a/cmake/FindReadline.cmake
+++ b/cmake/FindReadline.cmake
@@ -15,8 +15,11 @@
#
# READLINE_FOUND System has readline, include and lib dirs found
# GNU_READLINE_FOUND Version of readline found is GNU readline, not libedit!
+# LIBEDIT_FOUND Version of readline found is libedit, not GNU readline!
# Readline_INCLUDE_DIR The readline include directories.
# Readline_LIBRARY The readline library.
+# GNU_READLINE_LIBRARY The GNU readline library or empty string.
+# LIBEDIT_LIBRARY The libedit library or empty string.
find_path(Readline_ROOT_DIR
NAMES include/readline/readline.h
@@ -36,14 +39,18 @@ find_library(Readline_LIBRARY
NO_DEFAULT_PATH
)
-if(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
+find_library(Termcap_LIBRARY
+ NAMES tinfo termcap ncursesw ncurses cursesw curses
+)
+
+if(Readline_INCLUDE_DIR AND Readline_LIBRARY)
set(READLINE_FOUND TRUE)
-else(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
+else(Readline_INCLUDE_DIR AND Readline_LIBRARY)
FIND_LIBRARY(Readline_LIBRARY NAMES readline PATHS Readline_ROOT_DIR)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG Readline_INCLUDE_DIR Readline_LIBRARY )
MARK_AS_ADVANCED(Readline_INCLUDE_DIR Readline_LIBRARY)
-endif(Readline_INCLUDE_DIR AND Readline_LIBRARY AND Ncurses_LIBRARY)
+endif(Readline_INCLUDE_DIR AND Readline_LIBRARY)
mark_as_advanced(
Readline_ROOT_DIR
@@ -53,22 +60,30 @@ mark_as_advanced(
set(CMAKE_REQUIRED_INCLUDES ${Readline_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${Readline_LIBRARY})
-INCLUDE(CheckCXXSourceCompiles)
-CHECK_CXX_SOURCE_COMPILES(
-"
-#include <stdio.h>
-#include <readline/readline.h>
-int
-main()
-{
- char * s = rl_copy_text(0, 0);
-}
-" GNU_READLINE_FOUND)
-if(NOT Readline_LIBRARY)
- set(Readline_LIBRARY "")
-endif()
+include(CheckFunctionExists)
+check_function_exists(rl_copy_text HAVE_COPY_TEXT)
+check_function_exists(rl_filename_completion_function HAVE_COMPLETION_FUNCTION)
+
+if(NOT HAVE_COMPLETION_FUNCTION)
+ set(CMAKE_REQUIRED_LIBRARIES ${Readline_LIBRARY} ${Termcap_LIBRARY})
+ check_function_exists(rl_copy_text HAVE_COPY_TEXT_TC)
+ check_function_exists(rl_filename_completion_function HAVE_COMPLETION_FUNCTION_TC)
+ set(HAVE_COMPLETION_FUNCTION ${HAVE_COMPLETION_FUNCTION_TC})
+ set(HAVE_COPY_TEXT ${HAVE_COPY_TEXT_TC})
+ if(HAVE_COMPLETION_FUNCTION)
+ set(Readline_LIBRARY ${Readline_LIBRARY} ${Termcap_LIBRARY})
+ endif(HAVE_COMPLETION_FUNCTION)
+endif(NOT HAVE_COMPLETION_FUNCTION)
+
+set(LIBEDIT_LIBRARY "")
+set(GNU_READLINE_LIBRARY "")
+
+if(HAVE_COMPLETION_FUNCTION AND HAVE_COPY_TEXT)
+ set(GNU_READLINE_FOUND TRUE)
+ set(GNU_READLINE_LIBRARY ${Readline_LIBRARY})
+elseif(READLINE_FOUND AND NOT HAVE_COPY_TEXT)
+ set(LIBEDIT_FOUND TRUE)
+ set(LIBEDIT_LIBRARY ${Readline_LIBRARY})
+endif(HAVE_COMPLETION_FUNCTION AND HAVE_COPY_TEXT)
-if(Readline_LIBRARY AND OPENBSD)
- list(APPEND EXTRA_LIBRARIES curses)
-endif()
diff --git a/src/common/memwipe.h b/contrib/epee/include/memwipe.h
index c3b4ce8ab..c3b4ce8ab 100644
--- a/src/common/memwipe.h
+++ b/contrib/epee/include/memwipe.h
diff --git a/contrib/epee/include/net/http_auth.h b/contrib/epee/include/net/http_auth.h
index 841cebc17..71f56b570 100644
--- a/contrib/epee/include/net/http_auth.h
+++ b/contrib/epee/include/net/http_auth.h
@@ -71,8 +71,8 @@ namespace net_utils
std::uint32_t counter;
};
- http_server_auth() : user() {}
- http_server_auth(login credentials);
+ http_server_auth() : user(), rng() {}
+ http_server_auth(login credentials, std::function<void(size_t, uint8_t*)> r);
//! \return Auth response, or `boost::none` iff `request` had valid auth.
boost::optional<http_response_info> get_response(const http_request_info& request)
@@ -81,10 +81,13 @@ namespace net_utils
return do_get_response(request);
return boost::none;
}
+
private:
boost::optional<http_response_info> do_get_response(const http_request_info& request);
boost::optional<session> user;
+
+ std::function<void(size_t, uint8_t*)> rng;
};
//! Implements RFC 2617 digest auth. Digests from RFC 7616 can be added.
diff --git a/contrib/epee/include/net/http_protocol_handler.h b/contrib/epee/include/net/http_protocol_handler.h
index 652d8ff6f..b4485d1cd 100644
--- a/contrib/epee/include/net/http_protocol_handler.h
+++ b/contrib/epee/include/net/http_protocol_handler.h
@@ -160,6 +160,7 @@ namespace net_utils
struct custum_handler_config: public http_server_config
{
i_http_server_handler<t_connection_context>* m_phandler;
+ std::function<void(size_t, uint8_t*)> rng;
};
/************************************************************************/
@@ -176,7 +177,7 @@ namespace net_utils
: simple_http_connection_handler<t_connection_context>(psnd_hndlr, config),
m_config(config),
m_conn_context(conn_context),
- m_auth(m_config.m_user ? http_server_auth{*m_config.m_user} : http_server_auth{})
+ m_auth(m_config.m_user ? http_server_auth{*m_config.m_user, config.rng} : http_server_auth{})
{}
inline bool handle_request(const http_request_info& query_info, http_response_info& response)
{
diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h
index 8b8e31b51..1a97e610a 100644
--- a/contrib/epee/include/net/http_server_impl_base.h
+++ b/contrib/epee/include/net/http_server_impl_base.h
@@ -55,13 +55,14 @@ namespace epee
: m_net_server(external_io_service)
{}
- bool init(const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
+ bool init(std::function<void(size_t, uint8_t*)> rng, const std::string& bind_port = "0", const std::string& bind_ip = "0.0.0.0",
std::vector<std::string> access_control_origins = std::vector<std::string>(),
boost::optional<net_utils::http::login> user = boost::none)
{
//set self as callback handler
m_net_server.get_config_object().m_phandler = static_cast<t_child_class*>(this);
+ m_net_server.get_config_object().rng = std::move(rng);
//here set folder for hosting reqests
m_net_server.get_config_object().m_folder = "";
diff --git a/contrib/epee/include/net/network_throttle.hpp b/contrib/epee/include/net/network_throttle.hpp
index fffd22a6a..225ffee04 100644
--- a/contrib/epee/include/net/network_throttle.hpp
+++ b/contrib/epee/include/net/network_throttle.hpp
@@ -99,8 +99,6 @@ struct calculate_times_struct {
typedef calculate_times_struct calculate_times_struct;
-namespace cryptonote { class cryptonote_protocol_handler_base; } // a friend class // TODO friend not working
-
/***
@brief Access to simple throttles, with singlton to access global network limits
*/
@@ -117,7 +115,6 @@ class network_throttle_manager {
static boost::mutex m_lock_get_global_throttle_inreq;
static boost::mutex m_lock_get_global_throttle_out;
- friend class cryptonote::cryptonote_protocol_handler_base; // FRIEND - to directly access global throttle-s. !! REMEMBER TO USE LOCKS!
friend class connection_basic; // FRIEND - to directly access global throttle-s. !! REMEMBER TO USE LOCKS!
friend class connection_basic_pimpl; // ditto
diff --git a/contrib/epee/include/serialization/keyvalue_serialization.h b/contrib/epee/include/serialization/keyvalue_serialization.h
index d4413a71b..5791e1998 100644
--- a/contrib/epee/include/serialization/keyvalue_serialization.h
+++ b/contrib/epee/include/serialization/keyvalue_serialization.h
@@ -31,7 +31,6 @@
#include "misc_log_ex.h"
#include "enableable.h"
#include "keyvalue_serialization_overloads.h"
-#include "serialization/serialization.h"
namespace epee
{
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
index 8ced9d689..b4f7abca8 100644
--- a/contrib/epee/include/storages/levin_abstract_invoke2.h
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -60,8 +60,7 @@ namespace epee
LOG_ERROR("Failed to load_from_binary on command " << command);
return false;
}
- result_struct.load(stg_ret);
- return true;
+ return result_struct.load(stg_ret);
}
template<class t_arg, class t_transport>
@@ -105,9 +104,7 @@ namespace epee
LOG_ERROR("Failed to load_from_binary on command " << command);
return false;
}
- result_struct.load(stg_ret);
-
- return true;
+ return result_struct.load(stg_ret);
}
template<class t_result, class t_arg, class callback_t, class t_transport>
@@ -133,7 +130,12 @@ namespace epee
cb(LEVIN_ERROR_FORMAT, result_struct, context);
return false;
}
- result_struct.load(stg_ret);
+ if (!result_struct.load(stg_ret))
+ {
+ LOG_ERROR("Failed to load result struct on command " << command);
+ cb(LEVIN_ERROR_FORMAT, result_struct, context);
+ return false;
+ }
cb(code, result_struct, context);
return true;
}, inv_timeout);
@@ -176,7 +178,11 @@ namespace epee
boost::value_initialized<t_in_type> in_struct;
boost::value_initialized<t_out_type> out_struct;
- static_cast<t_in_type&>(in_struct).load(strg);
+ if (!static_cast<t_in_type&>(in_struct).load(strg))
+ {
+ LOG_ERROR("Failed to load in_struct in command " << command);
+ return -1;
+ }
int res = cb(command, static_cast<t_in_type&>(in_struct), static_cast<t_out_type&>(out_struct), context);
serialization::portable_storage strg_out;
static_cast<t_out_type&>(out_struct).store(strg_out);
@@ -200,7 +206,11 @@ namespace epee
return -1;
}
boost::value_initialized<t_in_type> in_struct;
- static_cast<t_in_type&>(in_struct).load(strg);
+ if (!static_cast<t_in_type&>(in_struct).load(strg))
+ {
+ LOG_ERROR("Failed to load in_struct in notify " << command);
+ return -1;
+ }
return cb(command, in_struct, context);
}
diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h
index 52aa09eba..36bb28627 100644
--- a/contrib/epee/include/storages/portable_storage_val_converters.h
+++ b/contrib/epee/include/storages/portable_storage_val_converters.h
@@ -28,6 +28,7 @@
#pragma once
+#include <time.h>
#include <boost/regex.hpp>
#include "misc_language.h"
@@ -149,9 +150,14 @@ POP_WARNINGS
else if (boost::regex_match (from, boost::regex("\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\dZ")))
{
// Convert to unix timestamp
+#ifdef HAVE_STRPTIME
+ struct tm tm;
+ if (strptime(from.c_str(), "%Y-%m-%dT%H:%M:%S", &tm))
+#else
std::tm tm = {};
std::istringstream ss(from);
if (ss >> std::get_time(&tm, "%Y-%m-%dT%H:%M:%S"))
+#endif
to = std::mktime(&tm);
} else
ASSERT_AND_THROW_WRONG_CONVERSION();
diff --git a/contrib/epee/src/CMakeLists.txt b/contrib/epee/src/CMakeLists.txt
index b6967e8fc..538c7ce91 100644
--- a/contrib/epee/src/CMakeLists.txt
+++ b/contrib/epee/src/CMakeLists.txt
@@ -26,12 +26,16 @@
# 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.
-add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp
+add_library(epee STATIC hex.cpp http_auth.cpp mlog.cpp net_utils_base.cpp string_tools.cpp wipeable_string.cpp memwipe.c
connection_basic.cpp network_throttle.cpp network_throttle-detail.cpp)
if (USE_READLINE AND GNU_READLINE_FOUND)
add_library(epee_readline STATIC readline_buffer.cpp)
endif()
+if(HAVE_C11)
+SET_PROPERTY(SOURCE memwipe.c PROPERTY COMPILE_FLAGS -std=c11)
+endif()
+
# Build and install libepee if we're building for GUI
if (BUILD_GUI_DEPS)
if(IOS)
@@ -49,7 +53,6 @@ endif()
target_link_libraries(epee
PUBLIC
- cncrypto
easylogging
${Boost_FILESYSTEM_LIBRARY}
PRIVATE
@@ -61,5 +64,5 @@ if (USE_READLINE AND GNU_READLINE_FOUND)
PUBLIC
easylogging
PRIVATE
- ${Readline_LIBRARY})
+ ${GNU_READLINE_LIBRARY})
endif()
diff --git a/contrib/epee/src/connection_basic.cpp b/contrib/epee/src/connection_basic.cpp
index 534044a79..5848d1268 100644
--- a/contrib/epee/src/connection_basic.cpp
+++ b/contrib/epee/src/connection_basic.cpp
@@ -78,7 +78,6 @@
// TODO:
#include "net/network_throttle-detail.hpp"
-#include "cryptonote_core/cryptonote_core.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.p2p"
diff --git a/contrib/epee/src/http_auth.cpp b/contrib/epee/src/http_auth.cpp
index f06f05528..5b8d892ff 100644
--- a/contrib/epee/src/http_auth.cpp
+++ b/contrib/epee/src/http_auth.cpp
@@ -66,7 +66,6 @@
#include <tuple>
#include <type_traits>
-#include "crypto/crypto.h"
#include "hex.h"
#include "md5_l.h"
#include "string_coding.h"
@@ -711,8 +710,8 @@ namespace epee
{
namespace http
{
- http_server_auth::http_server_auth(login credentials)
- : user(session{std::move(credentials)}) {
+ http_server_auth::http_server_auth(login credentials, std::function<void(size_t, uint8_t*)> r)
+ : user(session{std::move(credentials)}), rng(std::move(r)) {
}
boost::optional<http_response_info> http_server_auth::do_get_response(const http_request_info& request)
@@ -746,7 +745,7 @@ namespace epee
user->counter = 0;
{
std::array<std::uint8_t, 16> rand_128bit{{}};
- crypto::rand(rand_128bit.size(), rand_128bit.data());
+ rng(rand_128bit.size(), rand_128bit.data());
user->nonce = string_encoding::base64_encode(rand_128bit.data(), rand_128bit.size());
}
return create_digest_response(user->nonce, is_stale);
diff --git a/src/common/memwipe.c b/contrib/epee/src/memwipe.c
index da7e9f346..da7e9f346 100644
--- a/src/common/memwipe.c
+++ b/contrib/epee/src/memwipe.c
diff --git a/contrib/epee/src/wipeable_string.cpp b/contrib/epee/src/wipeable_string.cpp
index 894c47bbd..08a975e58 100644
--- a/contrib/epee/src/wipeable_string.cpp
+++ b/contrib/epee/src/wipeable_string.cpp
@@ -100,7 +100,7 @@ void wipeable_string::grow(size_t sz, size_t reserved)
wipefunc(buffer.data(), old_sz * sizeof(char));
buffer.reserve(reserved);
buffer.resize(sz);
- memcpy(buffer.data(), tmp.get(), sz * sizeof(char));
+ memcpy(buffer.data(), tmp.get(), old_sz * sizeof(char));
wipefunc(tmp.get(), old_sz * sizeof(char));
}
diff --git a/external/db_drivers/liblmdb/CMakeLists.txt b/external/db_drivers/liblmdb/CMakeLists.txt
index d3d3df6ad..3a09712de 100644
--- a/external/db_drivers/liblmdb/CMakeLists.txt
+++ b/external/db_drivers/liblmdb/CMakeLists.txt
@@ -54,3 +54,4 @@ if(${ARCH_WIDTH} EQUAL 32)
target_compile_definitions(lmdb
PUBLIC -DMDB_VL32)
endif()
+set_property(TARGET lmdb APPEND PROPERTY COMPILE_FLAGS "-fPIC")
diff --git a/external/easylogging++/CMakeLists.txt b/external/easylogging++/CMakeLists.txt
index 97d0bf571..8fe3fa487 100644
--- a/external/easylogging++/CMakeLists.txt
+++ b/external/easylogging++/CMakeLists.txt
@@ -54,4 +54,5 @@ if (BUILD_GUI_DEPS)
ARCHIVE DESTINATION ${lib_folder}
LIBRARY DESTINATION ${lib_folder})
endif()
+set_property(TARGET easylogging APPEND PROPERTY COMPILE_FLAGS "-fPIC")
diff --git a/external/easylogging++/ea_config.h b/external/easylogging++/ea_config.h
index c97858f30..4c74925d3 100644
--- a/external/easylogging++/ea_config.h
+++ b/external/easylogging++/ea_config.h
@@ -8,5 +8,7 @@
#define ELPP_NO_DEBUG_MACROS
#ifdef EASYLOGGING_CC
+#if !(!defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__ || defined __ANDROID__)
#define ELPP_FEATURE_CRASH_LOG
#endif
+#endif
diff --git a/external/miniupnpc/CMakeLists.txt b/external/miniupnpc/CMakeLists.txt
index bc9685699..2df8d474b 100644
--- a/external/miniupnpc/CMakeLists.txt
+++ b/external/miniupnpc/CMakeLists.txt
@@ -73,6 +73,13 @@ if (CMAKE_COMPILER_IS_GNUC)
endif ()
endif()
+# always add -fPIC
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
+set (CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fPIC")
+set (CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fPIC")
+set (CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -fPIC")
+set (CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -fPIC")
+
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/miniupnpcstrings.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/miniupnpcstrings.h)
include_directories (${CMAKE_CURRENT_BINARY_DIR})
diff --git a/external/unbound/CMakeLists.txt b/external/unbound/CMakeLists.txt
index 99ef62c5a..7d4da33e2 100644
--- a/external/unbound/CMakeLists.txt
+++ b/external/unbound/CMakeLists.txt
@@ -50,6 +50,7 @@ else()
add_definitions(-D_GNU_SOURCE)
endif()
add_definitions(-std=c99)
+add_definitions(-fPIC)
option(USE_ECDSA "Use ECDSA algorithms" ON)
option(USE_SHA2 "Enable SHA2 support" ON)
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index 88034a927..33c3341fa 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -1333,10 +1333,11 @@ public:
* @brief get a txpool transaction's metadata
*
* @param txid the transaction id of the transation to lookup
+ * @param meta the metadata to return
*
- * @return the metadata associated with that transaction
+ * @return true if the tx meta was found, false otherwise
*/
- virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const = 0;
+ virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const = 0;
/**
* @brief get a txpool transaction's blob
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index ee4368e86..d19399bec 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -1621,7 +1621,7 @@ void BlockchainLMDB::remove_txpool_tx(const crypto::hash& txid)
}
}
-txpool_tx_meta_t BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid) const
+bool BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -1632,12 +1632,14 @@ txpool_tx_meta_t BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid) co
MDB_val k = {sizeof(txid), (void *)&txid};
MDB_val v;
auto result = mdb_cursor_get(m_cur_txpool_meta, &k, &v, MDB_SET);
+ if (result == MDB_NOTFOUND)
+ return false;
if (result != 0)
throw1(DB_ERROR(lmdb_error("Error finding txpool tx meta: ", result).c_str()));
- const txpool_tx_meta_t meta = *(const txpool_tx_meta_t*)v.mv_data;
+ meta = *(const txpool_tx_meta_t*)v.mv_data;
TXN_POSTFIX_RDONLY();
- return meta;
+ return true;
}
bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const
@@ -2623,6 +2625,12 @@ bool BlockchainLMDB::batch_start(uint64_t batch_num_blocks, uint64_t batch_bytes
m_batch_active = true;
memset(&m_wcursors, 0, sizeof(m_wcursors));
+ if (m_tinfo.get())
+ {
+ if (m_tinfo->m_ti_rflags.m_rf_txn)
+ mdb_txn_reset(m_tinfo->m_ti_rtxn);
+ memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
+ }
LOG_PRINT_L3("batch transaction: begin");
return true;
@@ -2732,29 +2740,34 @@ void BlockchainLMDB::set_batch_transactions(bool batch_transactions)
bool BlockchainLMDB::block_rtxn_start(MDB_txn **mtxn, mdb_txn_cursors **mcur) const
{
bool ret = false;
+ mdb_threadinfo *tinfo;
if (m_write_txn && m_writer == boost::this_thread::get_id()) {
*mtxn = m_write_txn->m_txn;
*mcur = (mdb_txn_cursors *)&m_wcursors;
return ret;
}
- if (!m_tinfo.get())
+ /* Check for existing info and force reset if env doesn't match -
+ * only happens if env was opened/closed multiple times in same process
+ */
+ if (!(tinfo = m_tinfo.get()) || mdb_txn_env(tinfo->m_ti_rtxn) != m_env)
{
- m_tinfo.reset(new mdb_threadinfo);
- memset(&m_tinfo->m_ti_rcursors, 0, sizeof(m_tinfo->m_ti_rcursors));
- memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
- if (auto mdb_res = lmdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
+ tinfo = new mdb_threadinfo;
+ m_tinfo.reset(tinfo);
+ memset(&tinfo->m_ti_rcursors, 0, sizeof(tinfo->m_ti_rcursors));
+ memset(&tinfo->m_ti_rflags, 0, sizeof(tinfo->m_ti_rflags));
+ if (auto mdb_res = lmdb_txn_begin(m_env, NULL, MDB_RDONLY, &tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a read transaction for the db: ", mdb_res).c_str()));
ret = true;
- } else if (!m_tinfo->m_ti_rflags.m_rf_txn)
+ } else if (!tinfo->m_ti_rflags.m_rf_txn)
{
- if (auto mdb_res = lmdb_txn_renew(m_tinfo->m_ti_rtxn))
+ if (auto mdb_res = lmdb_txn_renew(tinfo->m_ti_rtxn))
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to renew a read transaction for the db: ", mdb_res).c_str()));
ret = true;
}
if (ret)
- m_tinfo->m_ti_rflags.m_rf_txn = true;
- *mtxn = m_tinfo->m_ti_rtxn;
- *mcur = &m_tinfo->m_ti_rcursors;
+ tinfo->m_ti_rflags.m_rf_txn = true;
+ *mtxn = tinfo->m_ti_rtxn;
+ *mcur = &tinfo->m_ti_rcursors;
if (ret)
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2772,28 +2785,9 @@ void BlockchainLMDB::block_txn_start(bool readonly)
{
if (readonly)
{
- bool didit = false;
- if (m_write_txn && m_writer == boost::this_thread::get_id())
- return;
- if (!m_tinfo.get())
- {
- m_tinfo.reset(new mdb_threadinfo);
- memset(&m_tinfo->m_ti_rcursors, 0, sizeof(m_tinfo->m_ti_rcursors));
- memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
- if (auto mdb_res = lmdb_txn_begin(m_env, NULL, MDB_RDONLY, &m_tinfo->m_ti_rtxn))
- throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a read transaction for the db: ", mdb_res).c_str()));
- didit = true;
- } else if (!m_tinfo->m_ti_rflags.m_rf_txn)
- {
- if (auto mdb_res = lmdb_txn_renew(m_tinfo->m_ti_rtxn))
- throw0(DB_ERROR_TXN_START(lmdb_error("Failed to renew a read transaction for the db: ", mdb_res).c_str()));
- didit = true;
- }
- if (didit)
- {
- m_tinfo->m_ti_rflags.m_rf_txn = true;
- LOG_PRINT_L3("BlockchainLMDB::" << __func__ << " RO");
- }
+ MDB_txn *mtxn;
+ mdb_txn_cursors *mcur;
+ block_rtxn_start(&mtxn, &mcur);
return;
}
@@ -2818,6 +2812,12 @@ void BlockchainLMDB::block_txn_start(bool readonly)
throw0(DB_ERROR_TXN_START(lmdb_error("Failed to create a transaction for the db: ", mdb_res).c_str()));
}
memset(&m_wcursors, 0, sizeof(m_wcursors));
+ if (m_tinfo.get())
+ {
+ if (m_tinfo->m_ti_rflags.m_rf_txn)
+ mdb_txn_reset(m_tinfo->m_ti_rtxn);
+ memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
+ }
} else if (m_writer != boost::this_thread::get_id())
throw0(DB_ERROR_TXN_START((std::string("Attempted to start new write txn when batch txn already exists in ")+__FUNCTION__).c_str()));
}
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 85b62b5db..ecd14f11b 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -246,7 +246,7 @@ public:
virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const;
virtual bool txpool_has_tx(const crypto::hash &txid) const;
virtual void remove_txpool_tx(const crypto::hash& txid);
- virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const;
+ virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const;
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const;
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const;
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const;
diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt
index bd32e0c55..6c55e8d2d 100644
--- a/src/blockchain_utilities/CMakeLists.txt
+++ b/src/blockchain_utilities/CMakeLists.txt
@@ -29,9 +29,9 @@
set(blocksdat "")
if(PER_BLOCK_CHECKPOINT)
if(APPLE)
- add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
+ add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
else()
- add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
+ add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
endif()
set(blocksdat "blocksdat.o")
endif()
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index 758deb7e4..edb8881e0 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -594,8 +594,8 @@ int main(int argc, char* argv[])
const command_line::arg_descriptor<std::string> arg_database = {
"database", available_dbs.c_str(), default_db_type
};
- const command_line::arg_descriptor<bool> arg_verify = {"verify",
- "Verify blocks and transactions during import", true};
+ const command_line::arg_descriptor<bool> arg_verify = {"guard-against-pwnage",
+ "Verify blocks and transactions during import (only disable if you exported the file yourself)", true};
const command_line::arg_descriptor<bool> arg_batch = {"batch",
"Batch transactions for faster import", true};
const command_line::arg_descriptor<bool> arg_resume = {"resume",
diff --git a/src/blocks/CMakeLists.txt b/src/blocks/CMakeLists.txt
index 3a866af5b..9317d585b 100644
--- a/src/blocks/CMakeLists.txt
+++ b/src/blocks/CMakeLists.txt
@@ -30,8 +30,8 @@ if(APPLE)
add_library(blocks STATIC blockexports.c)
set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C)
else()
- add_custom_command(OUTPUT blocks.o MAIN_DEPENDENCY blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat)
- add_custom_command(OUTPUT testnet_blocks.o MAIN_DEPENDENCY testnet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/testnet_blocks.o testnet_blocks.dat)
+ add_custom_command(OUTPUT blocks.o MAIN_DEPENDENCY blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat)
+ add_custom_command(OUTPUT testnet_blocks.o MAIN_DEPENDENCY testnet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/testnet_blocks.o testnet_blocks.dat)
add_library(blocks STATIC blocks.o testnet_blocks.o blockexports.c)
set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C)
endif()
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 7ad08ea83..7ce0229da 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -35,7 +35,6 @@ set(common_sources
download.cpp
util.cpp
i18n.cpp
- memwipe.c
password.cpp
perf_timer.cpp
threadpool.cpp
@@ -64,7 +63,6 @@ set(common_private_headers
util.h
varint.h
i18n.h
- memwipe.h
password.h
perf_timer.h
stack_trace.h
@@ -76,7 +74,8 @@ monero_private_headers(common
monero_add_library(common
${common_sources}
${common_headers}
- ${common_private_headers})
+ ${common_private_headers}
+ DEPENDS generate_translations_header)
target_link_libraries(common
PUBLIC
epee
@@ -92,9 +91,5 @@ target_link_libraries(common
${OPENSSL_LIBRARIES}
${EXTRA_LIBRARIES})
-if(HAVE_C11)
-SET_PROPERTY(SOURCE memwipe.c PROPERTY COMPILE_FLAGS -std=c11)
-endif()
-
#monero_install_headers(common
# ${common_headers})
diff --git a/src/common/apply_permutation.h b/src/common/apply_permutation.h
index 4fd952686..8684f14ce 100644
--- a/src/common/apply_permutation.h
+++ b/src/common/apply_permutation.h
@@ -30,6 +30,8 @@
// This algorithm is adapted from Raymond Chen's code:
// https://blogs.msdn.microsoft.com/oldnewthing/20170109-00/?p=95145
+#pragma once
+
#include <vector>
#include <functional>
#include "misc_log_ex.h"
diff --git a/src/common/i18n.cpp b/src/common/i18n.cpp
index 4a76e76fc..28a186bf0 100644
--- a/src/common/i18n.cpp
+++ b/src/common/i18n.cpp
@@ -35,6 +35,7 @@
#include "file_io_utils.h"
#include "common/util.h"
#include "common/i18n.h"
+#include "translation_files.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "i18n"
@@ -62,6 +63,7 @@ std::string i18n_get_language()
e = "en";
std::string language = e;
+ language = language.substr(0, language.find("."));
std::transform(language.begin(), language.end(), language.begin(), tolower);
return language;
}
@@ -137,25 +139,40 @@ int i18n_set_language(const char *directory, const char *base, std::string langu
i18n_log("Loading translations for language " << language);
boost::system::error_code ignored_ec;
- if (!boost::filesystem::exists(filename, ignored_ec)) {
+ if (boost::filesystem::exists(filename, ignored_ec)) {
+ if (!epee::file_io_utils::load_file_to_string(filename, contents)) {
+ i18n_log("Failed to load translations file: " << filename);
+ return -1;
+ }
+ } else {
i18n_log("Translations file not found: " << filename);
- const char *underscore = strchr(language.c_str(), '_');
- if (underscore) {
- std::string fallback_language = std::string(language, 0, underscore - language.c_str());
- filename = std::string(directory) + "/" + base + "_" + fallback_language + ".qm";
- i18n_log("Not found, loading translations for language " << fallback_language);
- if (!boost::filesystem::exists(filename, ignored_ec)) {
- i18n_log("Translations file not found: " << filename);
+ filename = std::string(base) + "_" + language + ".qm";
+ if (!find_embedded_file(filename, contents)) {
+ i18n_log("Embedded translations file not found: " << filename);
+ const char *underscore = strchr(language.c_str(), '_');
+ if (underscore) {
+ std::string fallback_language = std::string(language, 0, underscore - language.c_str());
+ filename = std::string(directory) + "/" + base + "_" + fallback_language + ".qm";
+ i18n_log("Loading translations for language " << fallback_language);
+ if (boost::filesystem::exists(filename, ignored_ec)) {
+ if (!epee::file_io_utils::load_file_to_string(filename, contents)) {
+ i18n_log("Failed to load translations file: " << filename);
+ return -1;
+ }
+ } else {
+ i18n_log("Translations file not found: " << filename);
+ filename = std::string(base) + "_" + fallback_language + ".qm";
+ if (!find_embedded_file(filename, contents)) {
+ i18n_log("Embedded translations file not found: " << filename);
+ return -1;
+ }
+ }
+ } else {
return -1;
}
}
}
- if (!epee::file_io_utils::load_file_to_string(filename, contents)) {
- i18n_log("Failed to load translations file: " << filename);
- return -1;
- }
-
data = (const unsigned char*)contents.c_str();
datalen = contents.size();
idx = 0;
diff --git a/src/common/password.cpp b/src/common/password.cpp
index dc0856160..011123300 100644
--- a/src/common/password.cpp
+++ b/src/common/password.cpp
@@ -46,7 +46,7 @@
#include "readline_buffer.h"
#endif
-#include "common/memwipe.h"
+#include "memwipe.h"
namespace
{
diff --git a/src/common/threadpool.cpp b/src/common/threadpool.cpp
index 20c5765b0..5d749e08e 100644
--- a/src/common/threadpool.cpp
+++ b/src/common/threadpool.cpp
@@ -34,6 +34,8 @@
#include "cryptonote_config.h"
#include "common/util.h"
+static __thread int depth = 0;
+
namespace tools
{
threadpool::threadpool() : running(true), active(0) {
@@ -60,11 +62,13 @@ threadpool::~threadpool() {
void threadpool::submit(waiter *obj, std::function<void()> f) {
entry e = {obj, f};
boost::unique_lock<boost::mutex> lock(mutex);
- if (active == max && !queue.empty()) {
+ if ((active == max && !queue.empty()) || depth > 0) {
// if all available threads are already running
// and there's work waiting, just run in current thread
lock.unlock();
+ ++depth;
f();
+ --depth;
} else {
if (obj)
obj->inc();
@@ -106,7 +110,9 @@ void threadpool::run() {
e = queue.front();
queue.pop_front();
lock.unlock();
+ ++depth;
e.f();
+ --depth;
if (e.wo)
e.wo->dec();
diff --git a/src/common/util.cpp b/src/common/util.cpp
index 2a2f50c4f..a4a435104 100644
--- a/src/common/util.cpp
+++ b/src/common/util.cpp
@@ -39,6 +39,7 @@
#include "wipeable_string.h"
using namespace epee;
+#include "crypto/crypto.h"
#include "util.h"
#include "memwipe.h"
#include "cryptonote_config.h"
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index fd71a87e7..764b30273 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -76,6 +76,7 @@ monero_add_library(cncrypto
${crypto_private_headers})
target_link_libraries(cncrypto
PUBLIC
+ epee
${Boost_SYSTEM_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
diff --git a/src/crypto/blake256.c b/src/crypto/blake256.c
index 1e43f9c4d..95b2a6927 100644
--- a/src/crypto/blake256.c
+++ b/src/crypto/blake256.c
@@ -157,7 +157,7 @@ void blake256_update(state *S, const uint8_t *data, uint64_t datalen) {
int left = S->buflen >> 3;
int fill = 64 - left;
- if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) {
+ if (left && (((datalen >> 3)) >= (unsigned) fill)) {
memcpy((void *) (S->buf + left), (void *) data, fill);
S->t[0] += 512;
if (S->t[0] == 0) S->t[1]++;
diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h
index a9665030d..c11e4aa2f 100644
--- a/src/crypto/chacha.h
+++ b/src/crypto/chacha.h
@@ -39,7 +39,7 @@
#if defined(__cplusplus)
#include <memory.h>
-#include "common/memwipe.h"
+#include "memwipe.h"
#include "hash.h"
namespace crypto {
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 0ce5e6d7a..a929302c1 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -41,7 +41,7 @@
#include "common/pod-class.h"
#include "common/util.h"
-#include "common/memwipe.h"
+#include "memwipe.h"
#include "generic-ops.h"
#include "hex.h"
#include "span.h"
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 821c21d84..c81901f4e 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -36,7 +36,6 @@
#include <cstring> // memcmp
#include <sstream>
#include <atomic>
-#include "serialization/serialization.h"
#include "serialization/variant.h"
#include "serialization/vector.h"
#include "serialization/binary_archive.h"
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp
index 1183fda06..929be0d5a 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.cpp
+++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp
@@ -34,7 +34,7 @@ using namespace epee;
#include "cryptonote_basic_impl.h"
#include "string_tools.h"
#include "serialization/binary_utils.h"
-#include "serialization/vector.h"
+#include "serialization/container.h"
#include "cryptonote_format_utils.h"
#include "cryptonote_config.h"
#include "misc_language.h"
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 21fa63842..5f6dc3bd6 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -35,6 +35,7 @@ using namespace epee;
#include <boost/algorithm/string.hpp>
#include "wipeable_string.h"
#include "string_tools.h"
+#include "serialization/string.h"
#include "cryptonote_format_utils.h"
#include "cryptonote_config.h"
#include "crypto/crypto.h"
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 709c5e852..69288a2b7 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -2933,7 +2933,7 @@ bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const
needed_fee += (blob_size % 1024) ? 1 : 0;
needed_fee *= fee_per_kb;
- if (fee < needed_fee * 0.98) // keep a little buffer on acceptance
+ if (fee < needed_fee - needed_fee / 50) // keep a little 2% buffer on acceptance - no integer overflow
{
MERROR_VER("transaction fee is not enough: " << print_money(fee) << ", minimum fee: " << print_money(needed_fee));
return false;
@@ -4198,9 +4198,9 @@ uint64_t Blockchain::get_txpool_tx_count(bool include_unrelayed_txes) const
return m_db->get_txpool_tx_count(include_unrelayed_txes);
}
-txpool_tx_meta_t Blockchain::get_txpool_tx_meta(const crypto::hash& txid) const
+bool Blockchain::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const
{
- return m_db->get_txpool_tx_meta(txid);
+ return m_db->get_txpool_tx_meta(txid, meta);
}
bool Blockchain::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 2d5307ac0..25e573a2c 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -914,7 +914,7 @@ namespace cryptonote
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta);
void remove_txpool_tx(const crypto::hash &txid);
uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const;
- txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const;
+ bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const;
bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const;
cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const;
bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = true) const;
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index e6f217463..8773c1f74 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -371,7 +371,12 @@ namespace cryptonote
try
{
LockedTXN lock(m_blockchain);
- txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(id);
+ txpool_tx_meta_t meta;
+ if (!m_blockchain.get_txpool_tx_meta(id, meta))
+ {
+ MERROR("Failed to find tx in txpool");
+ return false;
+ }
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(id);
if (!parse_and_validate_tx_from_blob(txblob, tx))
{
@@ -514,10 +519,13 @@ namespace cryptonote
{
try
{
- txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(it->first);
- meta.relayed = true;
- meta.last_relayed_time = now;
- m_blockchain.update_txpool_tx(it->first, meta);
+ txpool_tx_meta_t meta;
+ if (m_blockchain.get_txpool_tx_meta(it->first, meta))
+ {
+ meta.relayed = true;
+ meta.last_relayed_time = now;
+ m_blockchain.update_txpool_tx(it->first, meta);
+ }
}
catch (const std::exception &e)
{
@@ -696,7 +704,11 @@ namespace cryptonote
{
try
{
- meta = m_blockchain.get_txpool_tx_meta(tx_id_hash);
+ if (!m_blockchain.get_txpool_tx_meta(tx_id_hash, meta))
+ {
+ MERROR("Failed to get tx meta from txpool");
+ return false;
+ }
if (!meta.relayed)
// Do not include that transaction if in restricted mode and it's not relayed
continue;
@@ -918,7 +930,13 @@ namespace cryptonote
{
for (const crypto::hash &txid: it->second)
{
- txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(txid);
+ txpool_tx_meta_t meta;
+ if (!m_blockchain.get_txpool_tx_meta(txid, meta))
+ {
+ MERROR("Failed to find tx meta in txpool");
+ // continue, not fatal
+ continue;
+ }
if (!meta.double_spend_seen)
{
MDEBUG("Marking " << txid << " as double spending " << itk.k_image);
@@ -998,7 +1016,12 @@ namespace cryptonote
auto sorted_it = m_txs_by_fee_and_receive_time.begin();
while (sorted_it != m_txs_by_fee_and_receive_time.end())
{
- txpool_tx_meta_t meta = m_blockchain.get_txpool_tx_meta(sorted_it->second);
+ txpool_tx_meta_t meta;
+ if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
+ {
+ MERROR(" failed to find tx meta");
+ continue;
+ }
LOG_PRINT_L2("Considering " << sorted_it->second << ", size " << meta.blob_size << ", current block size " << total_size << "/" << max_total_size << ", current coinbase " << print_money(best_coinbase));
// Can not exceed maximum block size
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 8aef31a5a..6c350775d 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -876,6 +876,8 @@ namespace cryptonote
}
context.m_remote_blockchain_height = arg.current_blockchain_height;
+ if (context.m_remote_blockchain_height > m_core.get_target_blockchain_height())
+ m_core.set_target_blockchain_height(context.m_remote_blockchain_height);
std::vector<crypto::hash> block_hashes;
block_hashes.reserve(arg.blocks.size());
@@ -1059,6 +1061,11 @@ skip:
num_txs += block_entry.txs.size();
std::vector<tx_verification_context> tvc;
m_core.handle_incoming_txs(block_entry.txs, tvc, true, true, false);
+ if (tvc.size() != block_entry.txs.size())
+ {
+ LOG_ERROR_CCONTEXT("Internal error: tvc.size() != block_entry.txs.size()");
+ return true;
+ }
std::list<blobdata>::const_iterator it = block_entry.txs.begin();
for (size_t i = 0; i < tvc.size(); ++i, ++it)
{
diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt
index ad84db450..237105d06 100644
--- a/src/daemon/CMakeLists.txt
+++ b/src/daemon/CMakeLists.txt
@@ -29,9 +29,9 @@
set(blocksdat "")
if(PER_BLOCK_CHECKPOINT)
if(APPLE)
- add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
+ add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
else()
- add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
+ add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
endif()
set(blocksdat "blocksdat.o")
endif()
@@ -102,7 +102,7 @@ target_link_libraries(daemon
${Boost_SYSTEM_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${ZMQ_LIB}
- ${Readline_LIBRARY}
+ ${GNU_READLINE_LIBRARY}
${EXTRA_LIBRARIES})
set_property(TARGET daemon
PROPERTY
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index 6ac47fcb2..a47e74c71 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -269,7 +269,7 @@ int main(int argc, char const * argv[])
}
else
{
- std::cerr << "Unknown command" << std::endl;
+ std::cerr << "Unknown command: " << command.front() << std::endl;
return 1;
}
}
diff --git a/src/gen_multisig/CMakeLists.txt b/src/gen_multisig/CMakeLists.txt
index ff3c46862..8c534d213 100644
--- a/src/gen_multisig/CMakeLists.txt
+++ b/src/gen_multisig/CMakeLists.txt
@@ -43,8 +43,8 @@ target_link_libraries(gen_multisig
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
- ${Readline_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
+ ${GNU_READLINE_LIBRARY}
${EXTRA_LIBRARIES})
add_dependencies(gen_multisig
version)
diff --git a/src/mnemonics/CMakeLists.txt b/src/mnemonics/CMakeLists.txt
index 5ce2198ae..79964e873 100644
--- a/src/mnemonics/CMakeLists.txt
+++ b/src/mnemonics/CMakeLists.txt
@@ -57,6 +57,7 @@ monero_add_library(mnemonics
${mnemonics_private_headers})
target_link_libraries(mnemonics
PUBLIC
+ epee
easylogging
${Boost_SYSTEM_LIBRARY}
PRIVATE
diff --git a/src/mnemonics/electrum-words.cpp b/src/mnemonics/electrum-words.cpp
index ba67952aa..f44ad40aa 100644
--- a/src/mnemonics/electrum-words.cpp
+++ b/src/mnemonics/electrum-words.cpp
@@ -410,7 +410,7 @@ namespace crypto
std::vector<std::string> words_store;
uint32_t word_list_length = word_list.size();
- // 8 bytes -> 3 words. 8 digits base 16 -> 3 digits base 1626
+ // 4 bytes -> 3 words. 8 digits base 16 -> 3 digits base 1626
for (unsigned int i=0; i < len/4; i++, words += ' ')
{
uint32_t w1, w2, w3;
diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt
index 123b0a272..3fc053dc7 100644
--- a/src/p2p/CMakeLists.txt
+++ b/src/p2p/CMakeLists.txt
@@ -46,5 +46,6 @@ target_link_libraries(p2p
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
+ ${Boost_SERIALIZATION_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index 5ea2dcc7c..2df797360 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -47,7 +47,7 @@ extern "C" {
#include "hex.h"
#include "span.h"
-#include "serialization/serialization.h"
+#include "serialization/vector.h"
#include "serialization/debug_archive.h"
#include "serialization/binary_archive.h"
#include "serialization/json_archive.h"
diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt
index 748c6b8c1..19ea93902 100644
--- a/src/rpc/CMakeLists.txt
+++ b/src/rpc/CMakeLists.txt
@@ -101,6 +101,7 @@ target_link_libraries(rpc_base
epee
${Boost_REGEX_LIBRARY}
${Boost_THREAD_LIBRARY}
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
@@ -125,6 +126,7 @@ target_link_libraries(daemon_messages
target_link_libraries(daemon_rpc_server
LINK_PRIVATE
+ rpc
cryptonote_core
cryptonote_protocol
daemon_messages
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index a6109cb89..4966b107d 100644
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -106,8 +106,9 @@ namespace cryptonote
if (rpc_config->login)
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password());
+ auto rng = [](size_t len, uint8_t *ptr){ return crypto::rand(len, ptr); };
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
- std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
+ rng, std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
);
}
//------------------------------------------------------------------------------------------------------------------------------
diff --git a/src/rpc/zmq_server.cpp b/src/rpc/zmq_server.cpp
index afdff2328..6f06f4497 100644
--- a/src/rpc/zmq_server.cpp
+++ b/src/rpc/zmq_server.cpp
@@ -102,7 +102,7 @@ bool ZmqServer::addTCPSocket(std::string address, std::string port)
rep_socket.reset(new zmq::socket_t(context, ZMQ_REP));
- rep_socket->setsockopt(ZMQ_RCVTIMEO, DEFAULT_RPC_RECV_TIMEOUT_MS);
+ rep_socket->setsockopt(ZMQ_RCVTIMEO, &DEFAULT_RPC_RECV_TIMEOUT_MS, sizeof(DEFAULT_RPC_RECV_TIMEOUT_MS));
std::string bind_address = addr_prefix + address + std::string(":") + port;
rep_socket->bind(bind_address.c_str());
diff --git a/src/serialization/container.h b/src/serialization/container.h
new file mode 100644
index 000000000..978a59d2a
--- /dev/null
+++ b/src/serialization/container.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2014-2017, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include "serialization.h"
+
+namespace serialization
+{
+ namespace detail
+ {
+ template <typename Archive, class T>
+ bool serialize_container_element(Archive& ar, T& e)
+ {
+ return ::do_serialize(ar, e);
+ }
+
+ template <typename Archive>
+ bool serialize_container_element(Archive& ar, uint32_t& e)
+ {
+ ar.serialize_varint(e);
+ return true;
+ }
+
+ template <typename Archive>
+ bool serialize_container_element(Archive& ar, uint64_t& e)
+ {
+ ar.serialize_varint(e);
+ return true;
+ }
+
+ template <typename C>
+ void do_reserve(C &c, size_t N) {}
+ }
+}
+
+template <template <bool> class Archive, typename C>
+bool do_serialize_container(Archive<false> &ar, C &v)
+{
+ size_t cnt;
+ ar.begin_array(cnt);
+ if (!ar.stream().good())
+ return false;
+ v.clear();
+
+ // very basic sanity check
+ if (ar.remaining_bytes() < cnt) {
+ ar.stream().setstate(std::ios::failbit);
+ return false;
+ }
+
+ ::serialization::detail::do_reserve(v, cnt);
+
+ for (size_t i = 0; i < cnt; i++) {
+ if (i > 0)
+ ar.delimit_array();
+ typename C::value_type e;
+ if (!::serialization::detail::serialize_container_element(ar, e))
+ return false;
+ ::serialization::detail::do_add(v, std::move(e));
+ if (!ar.stream().good())
+ return false;
+ }
+ ar.end_array();
+ return true;
+}
+
+template <template <bool> class Archive, typename C>
+bool do_serialize_container(Archive<true> &ar, C &v)
+{
+ size_t cnt = v.size();
+ ar.begin_array(cnt);
+ for (auto i = v.begin(); i != v.end(); ++i)
+ {
+ if (!ar.stream().good())
+ return false;
+ if (i != v.begin())
+ ar.delimit_array();
+ if(!::serialization::detail::serialize_container_element(ar, const_cast<typename C::value_type&>(*i)))
+ return false;
+ if (!ar.stream().good())
+ return false;
+ }
+ ar.end_array();
+ return true;
+}
diff --git a/src/serialization/deque.h b/src/serialization/deque.h
new file mode 100644
index 000000000..994d3f195
--- /dev/null
+++ b/src/serialization/deque.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2014-2017, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include <deque>
+
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<false> &ar, std::deque<T> &v);
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::deque<T> &v);
+
+namespace serialization
+{
+ namespace detail
+ {
+ template <typename T>
+ void do_reserve(std::deque<T> &c, size_t N)
+ {
+ c.reserve(N);
+ }
+
+ template <typename T>
+ void do_add(std::deque<T> &c, T &&e)
+ {
+ c.emplace_back(std::move(e));
+ }
+ }
+}
+
+#include "serialization.h"
+
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<false> &ar, std::deque<T> &v) { return do_serialize_container(ar, v); }
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::deque<T> &v) { return do_serialize_container(ar, v); }
+
diff --git a/src/serialization/list.h b/src/serialization/list.h
index d0fb72163..d725458e7 100644
--- a/src/serialization/list.h
+++ b/src/serialization/list.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2015, The Monero Project
+// Copyright (c) 2014-2017, The Monero Project
//
// All rights reserved.
//
@@ -30,71 +30,29 @@
#pragma once
-#include "serialization.h"
+#include <list>
+
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<false> &ar, std::list<T> &v);
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::list<T> &v);
namespace serialization
{
namespace detail
{
- template <typename Archive, class T>
- bool serialize_list_element(Archive& ar, T& e)
- {
- return ::do_serialize(ar, e);
- }
-
- template <typename Archive>
- bool serialize_list_element(Archive& ar, uint64_t& e)
+ template <typename T>
+ void do_add(std::list<T> &c, T &&e)
{
- ar.serialize_varint(e);
- return true;
+ c.emplace_back(std::move(e));
}
}
}
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<false> &ar, std::list<T> &l)
-{
- size_t cnt;
- ar.begin_array(cnt);
- if (!ar.stream().good())
- return false;
- l.clear();
-
- // very basic sanity check
- if (ar.remaining_bytes() < cnt) {
- ar.stream().setstate(std::ios::failbit);
- return false;
- }
-
- for (size_t i = 0; i < cnt; i++) {
- if (i > 0)
- ar.delimit_array();
- l.push_back(T());
- T &t = l.back();
- if (!::serialization::detail::serialize_list_element(ar, t))
- return false;
- if (!ar.stream().good())
- return false;
- }
- ar.end_array();
- return true;
-}
+#include "serialization.h"
template <template <bool> class Archive, class T>
-bool do_serialize(Archive<true> &ar, std::list<T> &l)
-{
- size_t cnt = l.size();
- ar.begin_array(cnt);
- for (typename std::list<T>::iterator i = l.begin(); i != l.end(); ++i) {
- if (!ar.stream().good())
- return false;
- if (i != l.begin())
- ar.delimit_array();
- if(!::serialization::detail::serialize_list_element(ar, *i))
- return false;
- if (!ar.stream().good())
- return false;
- }
- ar.end_array();
- return true;
-}
+bool do_serialize(Archive<false> &ar, std::list<T> &v) { return do_serialize_container(ar, v); }
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::list<T> &v) { return do_serialize_container(ar, v); }
+
diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h
index 9e23f0791..56496c790 100644
--- a/src/serialization/serialization.h
+++ b/src/serialization/serialization.h
@@ -63,15 +63,17 @@ struct is_blob_type { typedef boost::false_type type; };
template <class T>
struct has_free_serializer { typedef boost::true_type type; };
-/*! \struct is_pair_type
+/*! \struct is_basic_type
*
* \brief a descriptor for dispatching serialize
*/
template <class T>
-struct is_pair_type { typedef boost::false_type type; };
+struct is_basic_type { typedef boost::false_type type; };
template<typename F, typename S>
-struct is_pair_type<std::pair<F,S>> { typedef boost::true_type type; };
+struct is_basic_type<std::pair<F,S>> { typedef boost::true_type type; };
+template<>
+struct is_basic_type<std::string> { typedef boost::true_type type; };
/*! \struct serializer
*
@@ -89,7 +91,7 @@ struct is_pair_type<std::pair<F,S>> { typedef boost::true_type type; };
template <class Archive, class T>
struct serializer{
static bool serialize(Archive &ar, T &v) {
- return serialize(ar, v, typename boost::is_integral<T>::type(), typename is_blob_type<T>::type(), typename is_pair_type<T>::type());
+ return serialize(ar, v, typename boost::is_integral<T>::type(), typename is_blob_type<T>::type(), typename is_basic_type<T>::type());
}
template<typename A>
static bool serialize(Archive &ar, T &v, boost::false_type, boost::true_type, A a) {
@@ -361,9 +363,3 @@ namespace serialization {
return r && check_stream_state(ar);
}
}
-
-#include "string.h"
-#include "vector.h"
-#include "list.h"
-#include "pair.h"
-#include "set.h"
diff --git a/src/serialization/set.h b/src/serialization/set.h
index 54b4eb3ab..e6eff62a9 100644
--- a/src/serialization/set.h
+++ b/src/serialization/set.h
@@ -30,98 +30,29 @@
#pragma once
-#include "serialization.h"
+#include <set>
template <template <bool> class Archive, class T>
bool do_serialize(Archive<false> &ar, std::set<T> &v);
template <template <bool> class Archive, class T>
bool do_serialize(Archive<true> &ar, std::set<T> &v);
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<false> &ar, std::unordered_set<T> &v);
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<true> &ar, std::unordered_set<T> &v);
namespace serialization
{
namespace detail
{
- template <typename Archive, class T>
- bool serialize_set_element(Archive& ar, T& e)
+ template <typename T>
+ void do_add(std::set<T> &c, T &&e)
{
- return ::do_serialize(ar, e);
- }
-
- template <typename Archive>
- bool serialize_set_element(Archive& ar, uint32_t& e)
- {
- ar.serialize_varint(e);
- return true;
- }
-
- template <typename Archive>
- bool serialize_set_element(Archive& ar, uint64_t& e)
- {
- ar.serialize_varint(e);
- return true;
+ c.insert(std::move(e));
}
}
}
-template <template <bool> class Archive, class T>
-bool do_serialize_set(Archive<false> &ar, T &v)
-{
- size_t cnt;
- ar.begin_array(cnt);
- if (!ar.stream().good())
- return false;
- v.clear();
-
- // very basic sanity check
- if (ar.remaining_bytes() < cnt) {
- ar.stream().setstate(std::ios::failbit);
- return false;
- }
-
- for (size_t i = 0; i < cnt; i++) {
- if (i > 0)
- ar.delimit_array();
- typename T::key_type k;
- if (!::serialization::detail::serialize_set_element(ar, k))
- return false;
- v.insert(std::move(k));
- if (!ar.stream().good())
- return false;
- }
- ar.end_array();
- return true;
-}
-
-template <template <bool> class Archive, class T>
-bool do_serialize_set(Archive<true> &ar, T &v)
-{
- size_t cnt = v.size();
- ar.begin_array(cnt);
- bool first = true;
- for (const typename T::key_type &k: v) {
- if (!ar.stream().good())
- return false;
- if (!first)
- ar.delimit_array();
- if(!::serialization::detail::serialize_set_element(ar, const_cast<typename T::key_type&>(k)))
- return false;
- if (!ar.stream().good())
- return false;
- first = false;
- }
- ar.end_array();
- return true;
-}
+#include "serialization.h"
template <template <bool> class Archive, class T>
-bool do_serialize(Archive<false> &ar, std::set<T> &v) { return do_serialize_set(ar, v); }
+bool do_serialize(Archive<false> &ar, std::set<T> &v) { return do_serialize_container(ar, v); }
template <template <bool> class Archive, class T>
-bool do_serialize(Archive<true> &ar, std::set<T> &v) { return do_serialize_set(ar, v); }
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<false> &ar, std::unordered_set<T> &v) { return do_serialize_set(ar, v); }
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<true> &ar, std::unordered_set<T> &v) { return do_serialize_set(ar, v); }
+bool do_serialize(Archive<true> &ar, std::set<T> &v) { return do_serialize_container(ar, v); }
+
diff --git a/src/serialization/unordered_set.h b/src/serialization/unordered_set.h
new file mode 100644
index 000000000..b277f0c4a
--- /dev/null
+++ b/src/serialization/unordered_set.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2014-2017, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include <set>
+
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<false> &ar, std::unordered_set<T> &v);
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::unordered_set<T> &v);
+
+namespace serialization
+{
+ namespace detail
+ {
+ template <typename T>
+ void do_add(std::unordered_set<T> &c, T &&e)
+ {
+ c.insert(std::move(e));
+ }
+ }
+}
+
+#include "serialization.h"
+
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<false> &ar, std::unordered_set<T> &v) { return do_serialize_container(ar, v); }
+template <template <bool> class Archive, class T>
+bool do_serialize(Archive<true> &ar, std::unordered_set<T> &v) { return do_serialize_container(ar, v); }
+
diff --git a/src/serialization/vector.h b/src/serialization/vector.h
index 12fd59558..9cf3d8272 100644
--- a/src/serialization/vector.h
+++ b/src/serialization/vector.h
@@ -30,6 +30,7 @@
#pragma once
+#include <vector>
#include "serialization.h"
template <template <bool> class Archive, class T>
@@ -37,91 +38,28 @@ bool do_serialize(Archive<false> &ar, std::vector<T> &v);
template <template <bool> class Archive, class T>
bool do_serialize(Archive<true> &ar, std::vector<T> &v);
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<false> &ar, std::deque<T> &v);
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<true> &ar, std::deque<T> &v);
-
namespace serialization
{
namespace detail
{
- template <typename Archive, class T>
- bool serialize_vector_element(Archive& ar, T& e)
- {
- return ::do_serialize(ar, e);
- }
-
- template <typename Archive>
- bool serialize_vector_element(Archive& ar, uint32_t& e)
+ template <typename T>
+ void do_reserve(std::vector<T> &c, size_t N)
{
- ar.serialize_varint(e);
- return true;
+ c.reserve(N);
}
- template <typename Archive>
- bool serialize_vector_element(Archive& ar, uint64_t& e)
+ template <typename T>
+ void do_add(std::vector<T> &c, T &&e)
{
- ar.serialize_varint(e);
- return true;
+ c.emplace_back(std::move(e));
}
}
}
-template <template <bool> class Archive, class T>
-bool do_serialize_vd(Archive<false> &ar, T &v)
-{
- size_t cnt;
- ar.begin_array(cnt);
- if (!ar.stream().good())
- return false;
- v.clear();
-
- // very basic sanity check
- if (ar.remaining_bytes() < cnt) {
- ar.stream().setstate(std::ios::failbit);
- return false;
- }
-
- v.reserve(cnt);
- for (size_t i = 0; i < cnt; i++) {
- if (i > 0)
- ar.delimit_array();
- v.resize(i+1);
- if (!::serialization::detail::serialize_vector_element(ar, v[i]))
- return false;
- if (!ar.stream().good())
- return false;
- }
- ar.end_array();
- return true;
-}
-
-template <template <bool> class Archive, class T>
-bool do_serialize_vd(Archive<true> &ar, T &v)
-{
- size_t cnt = v.size();
- ar.begin_array(cnt);
- for (size_t i = 0; i < cnt; i++) {
- if (!ar.stream().good())
- return false;
- if (i > 0)
- ar.delimit_array();
- if(!::serialization::detail::serialize_vector_element(ar, v[i]))
- return false;
- if (!ar.stream().good())
- return false;
- }
- ar.end_array();
- return true;
-}
+#include "container.h"
template <template <bool> class Archive, class T>
-bool do_serialize(Archive<false> &ar, std::vector<T> &v) { return do_serialize_vd(ar, v); }
+bool do_serialize(Archive<false> &ar, std::vector<T> &v) { return do_serialize_container(ar, v); }
template <template <bool> class Archive, class T>
-bool do_serialize(Archive<true> &ar, std::vector<T> &v) { return do_serialize_vd(ar, v); }
+bool do_serialize(Archive<true> &ar, std::vector<T> &v) { return do_serialize_container(ar, v); }
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<false> &ar, std::deque<T> &v) { return do_serialize_vd(ar, v); }
-template <template <bool> class Archive, class T>
-bool do_serialize(Archive<true> &ar, std::deque<T> &v) { return do_serialize_vd(ar, v); }
diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt
index beaacf0e9..f190ada8d 100644
--- a/src/simplewallet/CMakeLists.txt
+++ b/src/simplewallet/CMakeLists.txt
@@ -55,8 +55,8 @@ target_link_libraries(simplewallet
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
- ${Readline_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
+ ${GNU_READLINE_LIBRARY}
${EXTRA_LIBRARIES})
set_property(TARGET simplewallet
PROPERTY
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index bc3b3e926..79f619ab8 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -121,6 +121,7 @@ namespace
const command_line::arg_descriptor<std::string> arg_mnemonic_language = {"mnemonic-language", sw::tr("Language for mnemonic"), ""};
const command_line::arg_descriptor<std::string> arg_electrum_seed = {"electrum-seed", sw::tr("Specify Electrum seed for wallet recovery/creation"), ""};
const command_line::arg_descriptor<bool> arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false};
+ const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Create non-deterministic view and spend keys"), false};
const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<bool> arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false};
@@ -516,48 +517,55 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
bool simple_wallet::print_seed(bool encrypted)
{
bool success = false;
- std::string electrum_words;
+ std::string seed;
+ bool ready, multisig;
- if (m_wallet->multisig())
- {
- fail_msg_writer() << tr("wallet is multisig and has no seed");
- return true;
- }
if (m_wallet->watch_only())
{
fail_msg_writer() << tr("wallet is watch-only and has no seed");
return true;
}
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
- if (m_wallet->is_deterministic())
- {
- if (m_wallet->get_seed_language().empty())
- {
- std::string mnemonic_language = get_mnemonic_language();
- if (mnemonic_language.empty())
- return true;
- m_wallet->set_seed_language(mnemonic_language);
- }
- epee::wipeable_string seed_pass;
- if (encrypted)
+ multisig = m_wallet->multisig(&ready);
+ if (multisig)
+ {
+ if (!ready)
{
- auto pwd_container = tools::password_container::prompt(true, tr("Enter optional seed encryption passphrase, empty to see raw seed"));
- if (std::cin.eof() || !pwd_container)
- return true;
- seed_pass = pwd_container->password();
+ fail_msg_writer() << tr("wallet is multisig but not yet finalized");
+ return true;
}
+ }
+ else if (!m_wallet->is_deterministic())
+ {
+ fail_msg_writer() << tr("wallet is non-deterministic and has no seed");
+ return true;
+ }
- success = m_wallet->get_seed(electrum_words, seed_pass);
+ epee::wipeable_string seed_pass;
+ if (encrypted)
+ {
+#ifdef HAVE_READLINE
+ rdln::suspend_readline pause_readline;
+#endif
+ auto pwd_container = tools::password_container::prompt(true, tr("Enter optional seed encryption passphrase, empty to see raw seed"));
+ if (std::cin.eof() || !pwd_container)
+ return true;
+ seed_pass = pwd_container->password();
}
+ if (multisig)
+ success = m_wallet->get_multisig_seed(seed, seed_pass);
+ else if (m_wallet->is_deterministic())
+ success = m_wallet->get_seed(seed, seed_pass);
+
if (success)
{
- print_seed(electrum_words);
+ print_seed(seed);
}
else
{
- fail_msg_writer() << tr("wallet is non-deterministic and has no seed");
+ fail_msg_writer() << tr("Failed to retrieve seed");
}
return true;
}
@@ -1682,6 +1690,16 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::check_spend_proof, this, _1),
tr("check_spend_proof <txid> <signature_file> [<message>]"),
tr("Check a signature proving that the signer generated <txid>, optionally with a challenge string <message>."));
+ m_cmd_binder.set_handler("get_reserve_proof",
+ boost::bind(&simple_wallet::get_reserve_proof, this, _1),
+ tr("get_reserve_proof (all|<amount>) [<message>]"),
+ tr("Generate a signature proving that you own at least this much, optionally with a challenge string <message>.\n"
+ "If 'all' is specified, you prove the entire sum of all of your existing accounts' balances.\n"
+ "Otherwise, you prove the reserve of the smallest possible amount above <amount> available in your current account."));
+ m_cmd_binder.set_handler("check_reserve_proof",
+ boost::bind(&simple_wallet::check_reserve_proof, this, _1),
+ tr("check_reserve_proof <address> <signature_file> [<message>]"),
+ tr("Check a signature proving that the owner of <address> holds at least this much, optionally with a challenge string <message>."));
m_cmd_binder.set_handler("show_transfers",
boost::bind(&simple_wallet::show_transfers, this, _1),
tr("show_transfers [in|out|pending|failed|pool] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]"),
@@ -1762,11 +1780,11 @@ simple_wallet::simple_wallet()
tr("Turn this wallet into a multisig wallet, extra step for N-1/N wallets"));
m_cmd_binder.set_handler("export_multisig_info",
boost::bind(&simple_wallet::export_multisig, this, _1),
- tr("export_multisig <filename>"),
+ tr("export_multisig_info <filename>"),
tr("Export multisig info for other participants"));
m_cmd_binder.set_handler("import_multisig_info",
boost::bind(&simple_wallet::import_multisig, this, _1),
- tr("import_multisig <filename> [<filename>...]"),
+ tr("import_multisig_info <filename> [<filename>...]"),
tr("Import multisig info from other participants"));
m_cmd_binder.set_handler("sign_multisig",
boost::bind(&simple_wallet::sign_multisig, this, _1),
@@ -1778,7 +1796,7 @@ simple_wallet::simple_wallet()
tr("Submit a signed multisig transaction from a file"));
m_cmd_binder.set_handler("export_raw_multisig_tx",
boost::bind(&simple_wallet::export_raw_multisig, this, _1),
- tr("export_raw_multisig <filename>"),
+ tr("export_raw_multisig_tx <filename>"),
tr("Export a signed multisig transaction to a file"));
m_cmd_binder.set_handler("help",
boost::bind(&simple_wallet::help, this, _1),
@@ -1984,6 +2002,8 @@ static bool might_be_partial_seed(std::string words)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
+ std::string multisig_keys;
+
if (!handle_command_line(vm))
return false;
@@ -2001,49 +2021,91 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
std::string old_language;
// check for recover flag. if present, require electrum word list (only recovery option for now).
- if (m_restore_deterministic_wallet)
+ if (m_restore_deterministic_wallet || m_restore_multisig_wallet)
{
if (m_non_deterministic)
{
- fail_msg_writer() << tr("can't specify both --restore-deterministic-wallet and --non-deterministic");
+ fail_msg_writer() << tr("can't specify both --restore-deterministic-wallet or --restore-multisig-wallet and --non-deterministic");
return false;
}
if (!m_wallet_file.empty())
{
- fail_msg_writer() << tr("--restore-deterministic-wallet uses --generate-new-wallet, not --wallet-file");
+ if (m_restore_multisig_wallet)
+ fail_msg_writer() << tr("--restore-multisig-wallet uses --generate-new-wallet, not --wallet-file");
+ else
+ fail_msg_writer() << tr("--restore-deterministic-wallet uses --generate-new-wallet, not --wallet-file");
return false;
}
if (m_electrum_seed.empty())
{
- m_electrum_seed = "";
- do
+ if (m_restore_multisig_wallet)
{
- const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed: " : "Electrum seed continued: ";
- std::string electrum_seed = input_line(prompt);
- if (std::cin.eof())
- return false;
- if (electrum_seed.empty())
+ const char *prompt = "Specify multisig seed: ";
+ m_electrum_seed = input_line(prompt);
+ if (std::cin.eof())
+ return false;
+ if (m_electrum_seed.empty())
+ {
+ fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"multisig seed here\"");
+ return false;
+ }
+ }
+ else
+ {
+ m_electrum_seed = "";
+ do
{
- fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"words list here\"");
- return false;
- }
- m_electrum_seed += electrum_seed + " ";
- } while (might_be_partial_seed(m_electrum_seed));
+ const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed: " : "Electrum seed continued: ";
+ std::string electrum_seed = input_line(prompt);
+ if (std::cin.eof())
+ return false;
+ if (electrum_seed.empty())
+ {
+ fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"words list here\"");
+ return false;
+ }
+ m_electrum_seed += electrum_seed + " ";
+ } while (might_be_partial_seed(m_electrum_seed));
+ }
}
- if (!crypto::ElectrumWords::words_to_bytes(m_electrum_seed, m_recovery_key, old_language))
+ if (m_restore_multisig_wallet)
{
- fail_msg_writer() << tr("Electrum-style word list failed verification");
- return false;
+ if (!epee::string_tools::parse_hexstr_to_binbuff(m_electrum_seed, multisig_keys))
+ {
+ fail_msg_writer() << tr("Multisig seed failed verification");
+ return false;
+ }
+ }
+ else
+ {
+ if (!crypto::ElectrumWords::words_to_bytes(m_electrum_seed, m_recovery_key, old_language))
+ {
+ fail_msg_writer() << tr("Electrum-style word list failed verification");
+ return false;
+ }
}
+#ifdef HAVE_READLINE
+ rdln::suspend_readline pause_readline;
+#endif
auto pwd_container = tools::password_container::prompt(false, tr("Enter seed encryption passphrase, empty if none"));
if (std::cin.eof() || !pwd_container)
return false;
epee::wipeable_string seed_pass = pwd_container->password();
if (!seed_pass.empty())
- m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
+ {
+ if (m_restore_multisig_wallet)
+ {
+ crypto::secret_key key;
+ crypto::cn_slow_hash(seed_pass.data(), seed_pass.size(), (crypto::hash&)key);
+ sc_reduce32((unsigned char*)key.data);
+ multisig_keys = m_wallet->decrypt(multisig_keys, key, true);
+ }
+ else
+ m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
+ }
}
if (!m_generate_from_view_key.empty())
{
@@ -2354,7 +2416,11 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
m_wallet_file = m_generate_new;
- bool r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
+ bool r;
+ if (m_restore_multisig_wallet)
+ r = new_wallet(vm, multisig_keys, old_language);
+ else
+ r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
}
if (!m_restore_height && m_restoring)
@@ -2485,6 +2551,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_mnemonic_language = command_line::get_arg(vm, arg_mnemonic_language);
m_electrum_seed = command_line::get_arg(vm, arg_electrum_seed);
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
+ m_restore_multisig_wallet = command_line::get_arg(vm, arg_restore_multisig_wallet);
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon);
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
@@ -2495,7 +2562,8 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
!m_generate_from_keys.empty() ||
!m_generate_from_multisig_keys.empty() ||
!m_generate_from_json.empty() ||
- m_restore_deterministic_wallet;
+ m_restore_deterministic_wallet ||
+ m_restore_multisig_wallet;
return true;
}
@@ -2695,6 +2763,49 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
+ const std::string &multisig_keys, const std::string &old_language)
+{
+ auto rc = tools::wallet2::make_new(vm, password_prompter);
+ m_wallet = std::move(rc.first);
+ if (!m_wallet)
+ {
+ return false;
+ }
+
+ std::string mnemonic_language = old_language;
+
+ std::vector<std::string> language_list;
+ crypto::ElectrumWords::get_language_list(language_list);
+ if (mnemonic_language.empty() && std::find(language_list.begin(), language_list.end(), m_mnemonic_language) != language_list.end())
+ {
+ mnemonic_language = m_mnemonic_language;
+ }
+
+ m_wallet->set_seed_language(mnemonic_language);
+
+ try
+ {
+ m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys);
+ bool ready;
+ uint32_t threshold, total;
+ if (!m_wallet->multisig(&ready, &threshold, &total) || !ready)
+ {
+ fail_msg_writer() << tr("failed to generate new mutlisig wallet");
+ return false;
+ }
+ message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total
+ << m_wallet->get_account().get_public_address_str(m_wallet->testnet());
+ }
+ catch (const std::exception& e)
+ {
+ fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
+ return false;
+ }
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
{
if (!tools::wallet2::wallet_valid_path_format(m_wallet_file))
@@ -3206,6 +3317,13 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
{
if (!parse_subaddress_indices(local_args[0], subaddr_indices))
return true;
+ local_args.erase(local_args.begin());
+ }
+
+ if (local_args.size() > 0)
+ {
+ fail_msg_writer() << tr("usage: incoming_transfers [available|unavailable] [verbose] [index=<N>]");
+ return true;
}
tools::wallet2::transfer_container transfers;
@@ -4427,6 +4545,12 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::donate(const std::vector<std::string> &args_)
{
+ if(m_wallet->testnet())
+ {
+ fail_msg_writer() << tr("donations are not enabled on the testnet");
+ return true;
+ }
+
std::vector<std::string> local_args = args_;
if(local_args.empty() || local_args.size() > 5)
{
@@ -5011,6 +5135,110 @@ bool simple_wallet::check_spend_proof(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args)
+{
+ if(args.size() != 1 && args.size() != 2) {
+ fail_msg_writer() << tr("usage: get_reserve_proof (all|<amount>) [<message>]");
+ return true;
+ }
+
+ if (m_wallet->watch_only() || m_wallet->multisig())
+ {
+ fail_msg_writer() << tr("The reserve proof can be generated only by a full wallet");
+ return true;
+ }
+
+ boost::optional<std::pair<uint32_t, uint64_t>> account_minreserve;
+ if (args[0] != "all")
+ {
+ account_minreserve = std::pair<uint32_t, uint64_t>();
+ account_minreserve->first = m_current_subaddress_account;
+ if (!cryptonote::parse_amount(account_minreserve->second, args[0]))
+ {
+ fail_msg_writer() << tr("amount is wrong: ") << args[0];
+ return true;
+ }
+ }
+
+ if (!try_connect_to_daemon())
+ {
+ fail_msg_writer() << tr("failed to connect to the daemon");
+ return true;
+ }
+
+ if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
+
+ LOCK_IDLE_SCOPE();
+
+ try
+ {
+ const std::string sig_str = m_wallet->get_reserve_proof(account_minreserve, args.size() == 2 ? args[1] : "");
+ const std::string filename = "monero_reserve_proof";
+ if (epee::file_io_utils::save_string_to_file(filename, sig_str))
+ success_msg_writer() << tr("signature file saved to: ") << filename;
+ else
+ fail_msg_writer() << tr("failed to save signature file");
+ }
+ catch (const std::exception &e)
+ {
+ fail_msg_writer() << e.what();
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
+bool simple_wallet::check_reserve_proof(const std::vector<std::string> &args)
+{
+ if(args.size() != 2 && args.size() != 3) {
+ fail_msg_writer() << tr("usage: check_reserve_proof <address> <signature_file> [<message>]");
+ return true;
+ }
+
+ if (!try_connect_to_daemon())
+ {
+ fail_msg_writer() << tr("failed to connect to the daemon");
+ return true;
+ }
+
+ cryptonote::address_parse_info info;
+ if(!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), args[0], oa_prompter))
+ {
+ fail_msg_writer() << tr("failed to parse address");
+ return true;
+ }
+ if (info.is_subaddress)
+ {
+ fail_msg_writer() << tr("Address must not be a subaddress");
+ return true;
+ }
+
+ std::string sig_str;
+ if (!epee::file_io_utils::load_file_to_string(args[1], sig_str))
+ {
+ fail_msg_writer() << tr("failed to load signature file");
+ return true;
+ }
+
+ LOCK_IDLE_SCOPE();
+
+ try
+ {
+ uint64_t total, spent;
+ if (m_wallet->check_reserve_proof(info.address, args.size() == 3 ? args[2] : "", sig_str, total, spent))
+ {
+ success_msg_writer() << boost::format(tr("Good signature -- total: %s, spent: %s, unspent: %s")) % print_money(total) % print_money(spent) % print_money(total - spent);
+ }
+ else
+ {
+ fail_msg_writer() << tr("Bad signature");
+ }
+ }
+ catch (const std::exception& e)
+ {
+ fail_msg_writer() << e.what();
+ }
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
static std::string get_human_readable_timestamp(uint64_t ts)
{
char buffer[64];
@@ -6094,6 +6322,7 @@ bool simple_wallet::export_key_images(const std::vector<std::string> &args)
try
{
+ LOCK_IDLE_SCOPE();
if (!m_wallet->export_key_images(filename))
{
fail_msg_writer() << tr("failed to save file ") << filename;
@@ -6126,6 +6355,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
}
std::string filename = args[0];
+ LOCK_IDLE_SCOPE();
try
{
uint64_t spent = 0, unspent = 0;
@@ -6157,6 +6387,7 @@ bool simple_wallet::export_outputs(const std::vector<std::string> &args)
if (m_wallet->ask_password() && !get_and_verify_password()) { return true; }
std::string filename = args[0];
+ LOCK_IDLE_SCOPE();
try
{
std::vector<tools::wallet2::transfer_details> outs = m_wallet->export_outputs();
@@ -6255,6 +6486,7 @@ bool simple_wallet::import_outputs(const std::vector<std::string> &args)
boost::archive::binary_iarchive ar(iss);
ar >> outputs;
}
+ LOCK_IDLE_SCOPE();
size_t n_outputs = m_wallet->import_outputs(outputs);
success_msg_writer() << boost::lexical_cast<std::string>(n_outputs) << " outputs imported";
}
@@ -6473,6 +6705,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_command);
command_line::add_arg(desc_params, arg_restore_deterministic_wallet );
+ command_line::add_arg(desc_params, arg_restore_multisig_wallet );
command_line::add_arg(desc_params, arg_non_deterministic );
command_line::add_arg(desc_params, arg_electrum_seed );
command_line::add_arg(desc_params, arg_trusted_daemon);
@@ -6505,7 +6738,8 @@ int main(int argc, char* argv[])
std::vector<std::string> command = command_line::get_arg(*vm, arg_command);
if (!command.empty())
{
- w.process_command(command);
+ if (!w.process_command(command))
+ fail_msg_writer() << tr("Unknown command: ") << command.front();
w.stop();
w.deinit();
}
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index e5c00e542..45ed2c32c 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -92,6 +92,8 @@ namespace cryptonote
bool recover, bool two_random, const std::string &old_language);
bool new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address,
const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey);
+ bool new_wallet(const boost::program_options::variables_map& vm,
+ const std::string &multisig_keys, const std::string &old_language);
bool open_wallet(const boost::program_options::variables_map& vm);
bool close_wallet();
@@ -168,6 +170,8 @@ namespace cryptonote
bool check_tx_proof(const std::vector<std::string> &args);
bool get_spend_proof(const std::vector<std::string> &args);
bool check_spend_proof(const std::vector<std::string> &args);
+ bool get_reserve_proof(const std::vector<std::string> &args);
+ bool check_reserve_proof(const std::vector<std::string> &args);
bool show_transfers(const std::vector<std::string> &args);
bool unspent_outputs(const std::vector<std::string> &args);
bool rescan_blockchain(const std::vector<std::string> &args);
@@ -306,6 +310,7 @@ namespace cryptonote
crypto::secret_key m_recovery_key; // recovery key (used as random for wallet gen)
bool m_restore_deterministic_wallet; // recover flag
+ bool m_restore_multisig_wallet; // recover flag
bool m_non_deterministic; // old 2-random generation
bool m_trusted_daemon;
bool m_allow_mismatched_daemon_version;
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index fd0b65866..f96640d6e 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -1576,6 +1576,55 @@ bool WalletImpl::checkSpendProof(const std::string &txid_str, const std::string
}
}
+std::string WalletImpl::getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const {
+ try
+ {
+ m_status = Status_Ok;
+ boost::optional<std::pair<uint32_t, uint64_t>> account_minreserve;
+ if (!all)
+ {
+ account_minreserve = std::make_pair(account_index, amount);
+ }
+ return m_wallet->get_reserve_proof(account_minreserve, message);
+ }
+ catch (const std::exception &e)
+ {
+ m_status = Status_Error;
+ m_errorString = e.what();
+ return "";
+ }
+}
+
+bool WalletImpl::checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const {
+ cryptonote::address_parse_info info;
+ if (!cryptonote::get_account_address_from_str(info, m_wallet->testnet(), address))
+ {
+ m_status = Status_Error;
+ m_errorString = tr("Failed to parse address");
+ return false;
+ }
+ if (info.is_subaddress)
+ {
+ m_status = Status_Error;
+ m_errorString = tr("Address must not be a subaddress");
+ return false;
+ }
+
+ good = false;
+ try
+ {
+ m_status = Status_Ok;
+ good = m_wallet->check_reserve_proof(info.address, message, signature, total, spent);
+ return true;
+ }
+ catch (const std::exception &e)
+ {
+ m_status = Status_Error;
+ m_errorString = e.what();
+ return false;
+ }
+}
+
std::string WalletImpl::signMessage(const std::string &message)
{
return m_wallet->sign(message);
diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
index 01359ffc6..0b9fc851b 100644
--- a/src/wallet/api/wallet.h
+++ b/src/wallet/api/wallet.h
@@ -142,6 +142,8 @@ public:
virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received, bool &in_pool, uint64_t &confirmations);
virtual std::string getSpendProof(const std::string &txid, const std::string &message) const;
virtual bool checkSpendProof(const std::string &txid, const std::string &message, const std::string &signature, bool &good) const;
+ virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const;
+ virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const;
virtual std::string signMessage(const std::string &message);
virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const;
virtual void startRefresh();
diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
index ab1a48d6e..acecbb9dd 100644
--- a/src/wallet/api/wallet2_api.h
+++ b/src/wallet/api/wallet2_api.h
@@ -706,6 +706,12 @@ struct Wallet
virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received, bool &in_pool, uint64_t &confirmations) = 0;
virtual std::string getSpendProof(const std::string &txid, const std::string &message) const = 0;
virtual bool checkSpendProof(const std::string &txid, const std::string &message, const std::string &signature, bool &good) const = 0;
+ /*!
+ * \brief getReserveProof - Generates a proof that proves the reserve of unspent funds
+ * Parameters `account_index` and `amount` are ignored when `all` is true
+ */
+ virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const = 0;
+ virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const = 0;
/*
* \brief signMessage - sign a message with the spend private key
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index d6f4b9b98..1549c73b1 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -53,6 +53,7 @@ using namespace epee;
#include "profile_tools.h"
#include "crypto/crypto.h"
#include "serialization/binary_utils.h"
+#include "serialization/string.h"
#include "cryptonote_basic/blobdatatype.h"
#include "mnemonics/electrum-words.h"
#include "common/i18n.h"
@@ -62,7 +63,7 @@ using namespace epee;
#include "rapidjson/writer.h"
#include "rapidjson/stringbuffer.h"
#include "common/json_util.h"
-#include "common/memwipe.h"
+#include "memwipe.h"
#include "common/base58.h"
#include "ringct/rctSigs.h"
@@ -610,6 +611,7 @@ wallet2::wallet2(bool testnet, bool restricted):
m_min_output_value(0),
m_merge_destinations(false),
m_confirm_backlog(true),
+ m_confirm_backlog_threshold(0),
m_is_initialized(false),
m_restricted(restricted),
is_old_file_format(false),
@@ -733,6 +735,70 @@ bool wallet2::get_seed(std::string& electrum_words, const epee::wipeable_string
return true;
}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase, bool raw) const
+{
+ bool ready;
+ uint32_t threshold, total;
+ if (!multisig(&ready, &threshold, &total))
+ {
+ std::cout << "This is not a multisig wallet" << std::endl;
+ return false;
+ }
+ if (!ready)
+ {
+ std::cout << "This multisig wallet is not yet finalized" << std::endl;
+ return false;
+ }
+ if (!raw && seed_language.empty())
+ {
+ std::cout << "seed_language not set" << std::endl;
+ return false;
+ }
+
+ crypto::secret_key skey;
+ crypto::public_key pkey;
+ const account_keys &keys = get_account().get_keys();
+ std::string data;
+ data.append((const char*)&threshold, sizeof(uint32_t));
+ data.append((const char*)&total, sizeof(uint32_t));
+ skey = keys.m_spend_secret_key;
+ data.append((const char*)&skey, sizeof(skey));
+ pkey = keys.m_account_address.m_spend_public_key;
+ data.append((const char*)&pkey, sizeof(pkey));
+ skey = keys.m_view_secret_key;
+ data.append((const char*)&skey, sizeof(skey));
+ pkey = keys.m_account_address.m_view_public_key;
+ data.append((const char*)&pkey, sizeof(pkey));
+ for (const auto &skey: keys.m_multisig_keys)
+ data.append((const char*)&skey, sizeof(skey));
+ for (const auto &signer: m_multisig_signers)
+ data.append((const char*)&signer, sizeof(signer));
+
+ if (!passphrase.empty())
+ {
+ crypto::secret_key key;
+ crypto::cn_slow_hash(passphrase.data(), passphrase.size(), (crypto::hash&)key);
+ sc_reduce32((unsigned char*)key.data);
+ data = encrypt(data, key, true);
+ }
+
+ if (raw)
+ {
+ seed = epee::string_tools::buff_to_hex_nodelimer(data);
+ }
+ else
+ {
+ if (!crypto::ElectrumWords::bytes_to_words(data.data(), data.size(), seed, seed_language))
+ {
+ std::cout << "Failed to encode seed";
+ return false;
+ }
+ }
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
/*!
* \brief Gets the seed language
*/
@@ -1970,6 +2036,11 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height,
pull_hashes(0, blocks_start_height, short_chain_history, hashes);
if (hashes.size() <= 3)
return;
+ if (blocks_start_height < m_blockchain.offset())
+ {
+ MERROR("Blocks start before blockchain offset: " << blocks_start_height << " " << m_blockchain.offset());
+ return;
+ }
if (hashes.size() + current_index < stop_height) {
drop_from_short_history(short_chain_history, 3);
std::list<crypto::hash>::iterator right = hashes.end();
@@ -2646,6 +2717,97 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
* \brief Generates a wallet or restores one.
* \param wallet_ Name of wallet file
* \param password Password of wallet file
+ * \param multisig_data The multisig restore info and keys
+ */
+void wallet2::generate(const std::string& wallet_, const epee::wipeable_string& password,
+ const std::string& multisig_data)
+{
+ clear();
+ prepare_file_names(wallet_);
+
+ if (!wallet_.empty())
+ {
+ boost::system::error_code ignored_ec;
+ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file);
+ THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file);
+ }
+
+ m_account.generate(rct::rct2sk(rct::zero()), true, false);
+
+ THROW_WALLET_EXCEPTION_IF(multisig_data.size() < 32, error::invalid_multisig_seed);
+ size_t offset = 0;
+ uint32_t threshold = *(uint32_t*)(multisig_data.data() + offset);
+ offset += sizeof(uint32_t);
+ uint32_t total = *(uint32_t*)(multisig_data.data() + offset);
+ offset += sizeof(uint32_t);
+ THROW_WALLET_EXCEPTION_IF(threshold < 2, error::invalid_multisig_seed);
+ THROW_WALLET_EXCEPTION_IF(total != threshold && total != threshold + 1, error::invalid_multisig_seed);
+ const size_t n_multisig_keys = total == threshold ? 1 : threshold;
+ THROW_WALLET_EXCEPTION_IF(multisig_data.size() != 8 + 32 * (4 + n_multisig_keys + total), error::invalid_multisig_seed);
+
+ std::vector<crypto::secret_key> multisig_keys;
+ std::vector<crypto::public_key> multisig_signers;
+ crypto::secret_key spend_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset);
+ offset += sizeof(crypto::secret_key);
+ crypto::public_key spend_public_key = *(crypto::public_key*)(multisig_data.data() + offset);
+ offset += sizeof(crypto::public_key);
+ crypto::secret_key view_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset);
+ offset += sizeof(crypto::secret_key);
+ crypto::public_key view_public_key = *(crypto::public_key*)(multisig_data.data() + offset);
+ offset += sizeof(crypto::public_key);
+ for (size_t n = 0; n < n_multisig_keys; ++n)
+ {
+ multisig_keys.push_back(*(crypto::secret_key*)(multisig_data.data() + offset));
+ offset += sizeof(crypto::secret_key);
+ }
+ for (size_t n = 0; n < total; ++n)
+ {
+ multisig_signers.push_back(*(crypto::public_key*)(multisig_data.data() + offset));
+ offset += sizeof(crypto::public_key);
+ }
+
+ crypto::public_key calculated_view_public_key;
+ THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(view_secret_key, calculated_view_public_key), error::invalid_multisig_seed);
+ THROW_WALLET_EXCEPTION_IF(view_public_key != calculated_view_public_key, error::invalid_multisig_seed);
+ crypto::public_key local_signer;
+ THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(spend_secret_key, local_signer), error::invalid_multisig_seed);
+ THROW_WALLET_EXCEPTION_IF(std::find(multisig_signers.begin(), multisig_signers.end(), local_signer) == multisig_signers.end(), error::invalid_multisig_seed);
+ rct::key skey = rct::zero();
+ for (const auto &msk: multisig_keys)
+ sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes);
+ THROW_WALLET_EXCEPTION_IF(!(rct::rct2sk(skey) == spend_secret_key), error::invalid_multisig_seed);
+
+ m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys);
+ m_account.finalize_multisig(spend_public_key);
+
+ m_account_public_address = m_account.get_keys().m_account_address;
+ m_watch_only = false;
+ m_multisig = true;
+ m_multisig_threshold = threshold;
+ m_multisig_signers = multisig_signers;
+
+ if (!wallet_.empty())
+ {
+ bool r = store_keys(m_keys_file, password, false);
+ THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file);
+
+ r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_testnet));
+ if(!r) MERROR("String with address text not saved");
+ }
+
+ cryptonote::block b;
+ generate_genesis(b);
+ m_blockchain.push_back(get_block_hash(b));
+ add_subaddress_account(tr("Primary account"));
+
+ if (!wallet_.empty())
+ store();
+}
+
+/*!
+ * \brief Generates a wallet or restores one.
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
* \param recovery_param If it is a restore, the recovery key
* \param recover Whether it is a restore
* \param two_random Whether it is a non-deterministic wallet
@@ -2821,6 +2983,7 @@ void wallet2::generate(const std::string& wallet_, const epee::wipeable_string&
cryptonote::block b;
generate_genesis(b);
m_blockchain.push_back(get_block_hash(b));
+ add_subaddress_account(tr("Primary account"));
if (!wallet_.empty())
store();
@@ -5677,7 +5840,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
if (m_multisig)
{
crypto::public_key ignore = m_multisig_threshold == m_multisig_signers.size() ? crypto::null_pkey : multisig_signers.front();
- multisig_sigs.push_back({tx.rct_signatures, ignore, used_L, {}, msout});
+ multisig_sigs.push_back({tx.rct_signatures, ignore, used_L, std::unordered_set<crypto::public_key>(), msout});
if (m_multisig_threshold < m_multisig_signers.size())
{
@@ -5704,7 +5867,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet);
THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit);
THROW_WALLET_EXCEPTION_IF(cryptonote::get_transaction_prefix_hash(ms_tx) != prefix_hash, error::wallet_internal_error, "Multisig txes do not share prefix");
- multisig_sigs.push_back({ms_tx.rct_signatures, multisig_signers[signer_index], new_used_L, {}, msout});
+ multisig_sigs.push_back({ms_tx.rct_signatures, multisig_signers[signer_index], new_used_L, std::unordered_set<crypto::public_key>(), msout});
ms_tx.rct_signatures = tx.rct_signatures;
THROW_WALLET_EXCEPTION_IF(cryptonote::get_transaction_hash(ms_tx) != cryptonote::get_transaction_hash(tx), error::wallet_internal_error, "Multisig txes differ by more than the signatures");
@@ -6003,7 +6166,8 @@ void wallet2::light_wallet_get_unspent_outs()
add_tx_pub_key_to_extra(td.m_tx, tx_pub_key);
td.m_key_image = unspent_key_image;
- td.m_key_image_known = !m_watch_only;
+ td.m_key_image_known = !m_watch_only && !m_multisig;
+ td.m_key_image_partial = m_multisig;
td.m_amount = o.amount;
td.m_pk_index = 0;
td.m_internal_output_index = o.index;
@@ -6677,6 +6841,17 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof);
needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier);
+ uint64_t inputs = 0, outputs = needed_fee;
+ for (size_t idx: tx.selected_transfers) inputs += m_transfers[idx].amount();
+ for (const auto &o: tx.dsts) outputs += o.amount;
+
+ if (inputs < outputs)
+ {
+ LOG_PRINT_L2("We don't have enough for the basic fee, switching to adding_fee");
+ adding_fee = true;
+ goto skip_tx;
+ }
+
LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " <<
tx.selected_transfers.size() << " inputs");
if (use_rct)
@@ -6752,6 +6927,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
}
}
+skip_tx:
// if unused_*_indices is empty while unused_*_indices_per_subaddr has multiple elements, and if we still have something to pay,
// pop front of unused_*_indices_per_subaddr and have unused_*_indices point to the front of unused_*_indices_per_subaddr
if ((!dsts.empty() && dsts[0].amount > 0) || adding_fee)
@@ -6804,37 +6980,48 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet");
- std::map<uint32_t, uint64_t> balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account);
-
- if (subaddr_indices.empty())
- {
- // in case subaddress index wasn't specified, choose non-empty subaddress randomly (with index=0 being chosen last)
- if (balance_per_subaddr.count(0) == 1 && balance_per_subaddr.size() > 1)
- balance_per_subaddr.erase(0);
- auto i = balance_per_subaddr.begin();
- std::advance(i, crypto::rand<size_t>() % balance_per_subaddr.size());
- subaddr_indices.insert(i->first);
- }
- for (uint32_t i : subaddr_indices)
- LOG_PRINT_L2("Spending from subaddress index " << i);
+ std::map<uint32_t, std::pair<std::vector<size_t>, std::vector<size_t>>> unused_transfer_dust_indices_per_subaddr;
- // gather all dust and non-dust outputs of specified subaddress
+ // gather all dust and non-dust outputs of specified subaddress (if any) and below specified threshold (if any)
+ bool fund_found = false;
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
+ if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
{
+ fund_found = true;
if (below == 0 || td.amount() < below)
{
if ((td.is_rct()) || is_valid_decomposed_amount(td.amount()))
- unused_transfers_indices.push_back(i);
+ unused_transfer_dust_indices_per_subaddr[td.m_subaddr_index.minor].first.push_back(i);
else
- unused_dust_indices.push_back(i);
+ unused_transfer_dust_indices_per_subaddr[td.m_subaddr_index.minor].second.push_back(i);
}
}
}
+ THROW_WALLET_EXCEPTION_IF(!fund_found, error::wallet_internal_error, "No unlocked balance in the specified subaddress(es)");
+ THROW_WALLET_EXCEPTION_IF(unused_transfer_dust_indices_per_subaddr.empty(), error::wallet_internal_error, "The smallest amount found is not below the specified threshold");
- THROW_WALLET_EXCEPTION_IF(unused_transfers_indices.empty() && unused_dust_indices.empty(), error::not_enough_money, 0, 0, 0); // not sure if a new error class (something like 'cant_sweep_empty'?) should be introduced
+ if (subaddr_indices.empty())
+ {
+ // in case subaddress index wasn't specified, choose non-empty subaddress randomly (with index=0 being chosen last)
+ if (unused_transfer_dust_indices_per_subaddr.count(0) == 1 && unused_transfer_dust_indices_per_subaddr.size() > 1)
+ unused_transfer_dust_indices_per_subaddr.erase(0);
+ auto i = unused_transfer_dust_indices_per_subaddr.begin();
+ std::advance(i, crypto::rand<size_t>() % unused_transfer_dust_indices_per_subaddr.size());
+ unused_transfers_indices = i->second.first;
+ unused_dust_indices = i->second.second;
+ LOG_PRINT_L2("Spending from subaddress index " << i->first);
+ }
+ else
+ {
+ for (const auto& p : unused_transfer_dust_indices_per_subaddr)
+ {
+ unused_transfers_indices.insert(unused_transfers_indices.end(), p.second.first.begin(), p.second.first.end());
+ unused_dust_indices.insert(unused_dust_indices.end(), p.second.second.begin(), p.second.second.end());
+ LOG_PRINT_L2("Spending from subaddress index " << p.first);
+ }
+ }
return create_transactions_from(address, is_subaddress, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra, trusted_daemon);
}
@@ -7761,6 +7948,251 @@ bool wallet2::check_tx_proof(const crypto::hash &txid, const cryptonote::account
return false;
}
+std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t, uint64_t>> &account_minreserve, const std::string &message)
+{
+ THROW_WALLET_EXCEPTION_IF(m_watch_only || m_multisig, error::wallet_internal_error, "Reserve proof can only be generated by a full wallet");
+ THROW_WALLET_EXCEPTION_IF(balance_all() == 0, error::wallet_internal_error, "Zero balance");
+ THROW_WALLET_EXCEPTION_IF(account_minreserve && balance(account_minreserve->first) < account_minreserve->second, error::wallet_internal_error,
+ "Not enough balance in this account for the requested minimum reserve amount");
+
+ // determine which outputs to include in the proof
+ std::vector<size_t> selected_transfers;
+ for (size_t i = 0; i < m_transfers.size(); ++i)
+ {
+ const transfer_details &td = m_transfers[i];
+ if (!td.m_spent && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
+ selected_transfers.push_back(i);
+ }
+
+ if (account_minreserve)
+ {
+ // minimize the number of outputs included in the proof, by only picking the N largest outputs that can cover the requested min reserve amount
+ std::sort(selected_transfers.begin(), selected_transfers.end(), [&](const size_t a, const size_t b)
+ { return m_transfers[a].amount() > m_transfers[b].amount(); });
+ while (selected_transfers.size() >= 2 && m_transfers[selected_transfers[1]].amount() >= account_minreserve->second)
+ selected_transfers.erase(selected_transfers.begin());
+ size_t sz = 0;
+ uint64_t total = 0;
+ while (total < account_minreserve->second)
+ {
+ total += m_transfers[selected_transfers[sz]].amount();
+ ++sz;
+ }
+ selected_transfers.resize(sz);
+ }
+
+ // compute signature prefix hash
+ std::string prefix_data = message;
+ prefix_data.append((const char*)&m_account.get_keys().m_account_address, sizeof(cryptonote::account_public_address));
+ for (size_t i = 0; i < selected_transfers.size(); ++i)
+ {
+ prefix_data.append((const char*)&m_transfers[selected_transfers[i]].m_key_image, sizeof(crypto::key_image));
+ }
+ crypto::hash prefix_hash;
+ crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
+
+ // generate proof entries
+ std::vector<reserve_proof_entry> proofs(selected_transfers.size());
+ std::unordered_set<cryptonote::subaddress_index> subaddr_indices = { {0,0} };
+ for (size_t i = 0; i < selected_transfers.size(); ++i)
+ {
+ const transfer_details &td = m_transfers[selected_transfers[i]];
+ reserve_proof_entry& proof = proofs[i];
+ proof.txid = td.m_txid;
+ proof.index_in_tx = td.m_internal_output_index;
+ proof.key_image = td.m_key_image;
+ subaddr_indices.insert(td.m_subaddr_index);
+
+ // get tx pub key
+ const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
+ THROW_WALLET_EXCEPTION_IF(tx_pub_key == crypto::null_pkey, error::wallet_internal_error, "The tx public key isn't found");
+ const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
+
+ // determine which tx pub key was used for deriving the output key
+ const crypto::public_key *tx_pub_key_used = &tx_pub_key;
+ for (int i = 0; i < 2; ++i)
+ {
+ proof.shared_secret = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(*tx_pub_key_used), rct::sk2rct(m_account.get_keys().m_view_secret_key)));
+ crypto::key_derivation derivation;
+ THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(proof.shared_secret, rct::rct2sk(rct::I), derivation),
+ error::wallet_internal_error, "Failed to generate key derivation");
+ crypto::public_key subaddress_spendkey;
+ THROW_WALLET_EXCEPTION_IF(!derive_subaddress_public_key(td.get_public_key(), derivation, proof.index_in_tx, subaddress_spendkey),
+ error::wallet_internal_error, "Failed to derive subaddress public key");
+ if (m_subaddresses.count(subaddress_spendkey) == 1)
+ break;
+ THROW_WALLET_EXCEPTION_IF(additional_tx_pub_keys.empty(), error::wallet_internal_error,
+ "Normal tx pub key doesn't derive the expected output, while the additional tx pub keys are empty");
+ THROW_WALLET_EXCEPTION_IF(i == 1, error::wallet_internal_error,
+ "Neither normal tx pub key nor additional tx pub key derive the expected output key");
+ tx_pub_key_used = &additional_tx_pub_keys[proof.index_in_tx];
+ }
+
+ // generate signature for shared secret
+ crypto::generate_tx_proof(prefix_hash, m_account.get_keys().m_account_address.m_view_public_key, *tx_pub_key_used, boost::none, proof.shared_secret, m_account.get_keys().m_view_secret_key, proof.shared_secret_sig);
+
+ // derive ephemeral secret key
+ crypto::key_image ki;
+ cryptonote::keypair ephemeral;
+ const bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, td.get_public_key(), tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, ephemeral, ki);
+ THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
+ THROW_WALLET_EXCEPTION_IF(ephemeral.pub != td.get_public_key(), error::wallet_internal_error, "Derived public key doesn't agree with the stored one");
+
+ // generate signature for key image
+ const std::vector<const crypto::public_key*> pubs = { &ephemeral.pub };
+ crypto::generate_ring_signature(prefix_hash, td.m_key_image, &pubs[0], 1, ephemeral.sec, 0, &proof.key_image_sig);
+ }
+
+ // collect all subaddress spend keys that received those outputs and generate their signatures
+ std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
+ for (const cryptonote::subaddress_index &index : subaddr_indices)
+ {
+ crypto::secret_key subaddr_spend_skey = m_account.get_keys().m_spend_secret_key;
+ if (!index.is_zero())
+ {
+ crypto::secret_key m = cryptonote::get_subaddress_secret_key(m_account.get_keys().m_view_secret_key, index);
+ crypto::secret_key tmp = subaddr_spend_skey;
+ sc_add((unsigned char*)&subaddr_spend_skey, (unsigned char*)&m, (unsigned char*)&tmp);
+ }
+ crypto::public_key subaddr_spend_pkey;
+ secret_key_to_public_key(subaddr_spend_skey, subaddr_spend_pkey);
+ crypto::generate_signature(prefix_hash, subaddr_spend_pkey, subaddr_spend_skey, subaddr_spendkeys[subaddr_spend_pkey]);
+ }
+
+ // serialize & encode
+ std::ostringstream oss;
+ boost::archive::portable_binary_oarchive ar(oss);
+ ar << proofs << subaddr_spendkeys;
+ return "ReserveProofV1" + tools::base58::encode(oss.str());
+}
+
+bool wallet2::check_reserve_proof(const cryptonote::account_public_address &address, const std::string &message, const std::string &sig_str, uint64_t &total, uint64_t &spent)
+{
+ uint32_t rpc_version;
+ THROW_WALLET_EXCEPTION_IF(!check_connection(&rpc_version), error::wallet_internal_error, "Failed to connect to daemon: " + get_daemon_address());
+ THROW_WALLET_EXCEPTION_IF(rpc_version < MAKE_CORE_RPC_VERSION(1, 0), error::wallet_internal_error, "Daemon RPC version is too old");
+
+ static constexpr char header[] = "ReserveProofV1";
+ THROW_WALLET_EXCEPTION_IF(!boost::string_ref{sig_str}.starts_with(header), error::wallet_internal_error,
+ "Signature header check error");
+
+ std::string sig_decoded;
+ THROW_WALLET_EXCEPTION_IF(!tools::base58::decode(sig_str.substr(std::strlen(header)), sig_decoded), error::wallet_internal_error,
+ "Signature decoding error");
+
+ std::istringstream iss(sig_decoded);
+ boost::archive::portable_binary_iarchive ar(iss);
+ std::vector<reserve_proof_entry> proofs;
+ std::unordered_map<crypto::public_key, crypto::signature> subaddr_spendkeys;
+ ar >> proofs >> subaddr_spendkeys;
+
+ THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(address.m_spend_public_key) == 0, error::wallet_internal_error,
+ "The given address isn't found in the proof");
+
+ // compute signature prefix hash
+ std::string prefix_data = message;
+ prefix_data.append((const char*)&address, sizeof(cryptonote::account_public_address));
+ for (size_t i = 0; i < proofs.size(); ++i)
+ {
+ prefix_data.append((const char*)&proofs[i].key_image, sizeof(crypto::key_image));
+ }
+ crypto::hash prefix_hash;
+ crypto::cn_fast_hash(prefix_data.data(), prefix_data.size(), prefix_hash);
+
+ // fetch txes from daemon
+ COMMAND_RPC_GET_TRANSACTIONS::request gettx_req;
+ COMMAND_RPC_GET_TRANSACTIONS::response gettx_res;
+ for (size_t i = 0; i < proofs.size(); ++i)
+ gettx_req.txs_hashes.push_back(epee::string_tools::pod_to_hex(proofs[i].txid));
+ m_daemon_rpc_mutex.lock();
+ bool ok = net_utils::invoke_http_json("/gettransactions", gettx_req, gettx_res, m_http_client);
+ m_daemon_rpc_mutex.unlock();
+ THROW_WALLET_EXCEPTION_IF(!ok || gettx_res.txs.size() != proofs.size(),
+ error::wallet_internal_error, "Failed to get transaction from daemon");
+
+ // check spent status
+ COMMAND_RPC_IS_KEY_IMAGE_SPENT::request kispent_req;
+ COMMAND_RPC_IS_KEY_IMAGE_SPENT::response kispent_res;
+ for (size_t i = 0; i < proofs.size(); ++i)
+ kispent_req.key_images.push_back(epee::string_tools::pod_to_hex(proofs[i].key_image));
+ m_daemon_rpc_mutex.lock();
+ ok = epee::net_utils::invoke_http_json("/is_key_image_spent", kispent_req, kispent_res, m_http_client, rpc_timeout);
+ m_daemon_rpc_mutex.unlock();
+ THROW_WALLET_EXCEPTION_IF(!ok || kispent_res.spent_status.size() != proofs.size(),
+ error::wallet_internal_error, "Failed to get key image spent status from daemon");
+
+ total = spent = 0;
+ for (size_t i = 0; i < proofs.size(); ++i)
+ {
+ const reserve_proof_entry& proof = proofs[i];
+ THROW_WALLET_EXCEPTION_IF(gettx_res.txs[i].in_pool, error::wallet_internal_error, "Tx is unconfirmed");
+
+ cryptonote::blobdata tx_data;
+ ok = string_tools::parse_hexstr_to_binbuff(gettx_res.txs[i].as_hex, tx_data);
+ THROW_WALLET_EXCEPTION_IF(!ok, error::wallet_internal_error, "Failed to parse transaction from daemon");
+
+ crypto::hash tx_hash, tx_prefix_hash;
+ cryptonote::transaction tx;
+ THROW_WALLET_EXCEPTION_IF(!cryptonote::parse_and_validate_tx_from_blob(tx_data, tx, tx_hash, tx_prefix_hash), error::wallet_internal_error,
+ "Failed to validate transaction from daemon");
+ THROW_WALLET_EXCEPTION_IF(tx_hash != proof.txid, error::wallet_internal_error, "Failed to get the right transaction from daemon");
+
+ THROW_WALLET_EXCEPTION_IF(proof.index_in_tx >= tx.vout.size(), error::wallet_internal_error, "index_in_tx is out of bound");
+
+ const cryptonote::txout_to_key* const out_key = boost::get<cryptonote::txout_to_key>(std::addressof(tx.vout[proof.index_in_tx].target));
+ THROW_WALLET_EXCEPTION_IF(!out_key, error::wallet_internal_error, "Output key wasn't found")
+
+ // get tx pub key
+ const crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
+ THROW_WALLET_EXCEPTION_IF(tx_pub_key == crypto::null_pkey, error::wallet_internal_error, "The tx public key isn't found");
+ const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx);
+
+ // check singature for shared secret
+ ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, tx_pub_key, boost::none, proof.shared_secret, proof.shared_secret_sig);
+ if (!ok && additional_tx_pub_keys.size() == tx.vout.size())
+ ok = crypto::check_tx_proof(prefix_hash, address.m_view_public_key, additional_tx_pub_keys[proof.index_in_tx], boost::none, proof.shared_secret, proof.shared_secret_sig);
+ if (!ok)
+ return false;
+
+ // check signature for key image
+ const std::vector<const crypto::public_key*> pubs = { &out_key->key };
+ ok = crypto::check_ring_signature(prefix_hash, proof.key_image, &pubs[0], 1, &proof.key_image_sig);
+ if (!ok)
+ return false;
+
+ // check if the address really received the fund
+ crypto::key_derivation derivation;
+ THROW_WALLET_EXCEPTION_IF(!crypto::generate_key_derivation(proof.shared_secret, rct::rct2sk(rct::I), derivation), error::wallet_internal_error, "Failed to generate key derivation");
+ crypto::public_key subaddr_spendkey;
+ crypto::derive_subaddress_public_key(out_key->key, derivation, proof.index_in_tx, subaddr_spendkey);
+ THROW_WALLET_EXCEPTION_IF(subaddr_spendkeys.count(subaddr_spendkey) == 0, error::wallet_internal_error,
+ "The address doesn't seem to have received the fund");
+
+ // check amount
+ uint64_t amount = tx.vout[proof.index_in_tx].amount;
+ if (amount == 0)
+ {
+ // decode rct
+ crypto::secret_key shared_secret;
+ crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret);
+ rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx];
+ rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret));
+ amount = rct::h2d(ecdh_info.amount);
+ }
+ total += amount;
+ if (kispent_res.spent_status[i])
+ spent += amount;
+ }
+
+ // check signatures for all subaddress spend keys
+ for (const auto &i : subaddr_spendkeys)
+ {
+ if (!crypto::check_signature(prefix_hash, i.first, i.second))
+ return false;
+ }
+ return true;
+}
+
std::string wallet2::get_wallet_file() const
{
return m_wallet_file;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index b1115f67b..04d789f18 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -433,9 +433,28 @@ namespace tools
bool m_is_subaddress;
};
+ struct reserve_proof_entry
+ {
+ crypto::hash txid;
+ uint64_t index_in_tx;
+ crypto::public_key shared_secret;
+ crypto::key_image key_image;
+ crypto::signature shared_secret_sig;
+ crypto::signature key_image_sig;
+ };
+
typedef std::tuple<uint64_t, crypto::public_key, rct::key> get_outs_entry;
/*!
+ * \brief Generates a wallet or restores one.
+ * \param wallet_ Name of wallet file
+ * \param password Password of wallet file
+ * \param multisig_data The multisig restore info and keys
+ */
+ void generate(const std::string& wallet_, const epee::wipeable_string& password,
+ const std::string& multisig_data);
+
+ /*!
* \brief Generates a wallet or restores one.
* \param wallet_ Name of wallet file
* \param password Password of wallet file
@@ -610,6 +629,7 @@ namespace tools
bool watch_only() const { return m_watch_only; }
bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const;
bool has_multisig_partial_key_images() const;
+ bool get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase = std::string(), bool raw = true) const;
// locked & unlocked balance of given or current subaddress account
uint64_t balance(uint32_t subaddr_index_major) const;
@@ -826,6 +846,26 @@ namespace tools
std::string get_spend_proof(const crypto::hash &txid, const std::string &message);
bool check_spend_proof(const crypto::hash &txid, const std::string &message, const std::string &sig_str);
+
+ /*!
+ * \brief Generates a proof that proves the reserve of unspent funds
+ * \param account_minreserve When specified, collect outputs only belonging to the given account and prove the smallest reserve above the given amount
+ * When unspecified, proves for all unspent outputs across all accounts
+ * \param message Arbitrary challenge message to be signed together
+ * \return Signature string
+ */
+ std::string get_reserve_proof(const boost::optional<std::pair<uint32_t, uint64_t>> &account_minreserve, const std::string &message);
+ /*!
+ * \brief Verifies a proof of reserve
+ * \param address The signer's address
+ * \param message Challenge message used for signing
+ * \param sig_str Signature string
+ * \param total [OUT] the sum of funds included in the signature
+ * \param spent [OUT] the sum of spent funds included in the signature
+ * \return true if the signature verifies correctly
+ */
+ bool check_reserve_proof(const cryptonote::account_public_address &address, const std::string &message, const std::string &sig_str, uint64_t &total, uint64_t &spent);
+
/*!
* \brief GUI Address book get/store
*/
@@ -1109,6 +1149,7 @@ BOOST_CLASS_VERSION(tools::wallet2::pool_payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 7)
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 5)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 17)
+BOOST_CLASS_VERSION(tools::wallet2::reserve_proof_entry, 0)
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 2)
@@ -1392,6 +1433,17 @@ namespace boost
}
template <class Archive>
+ inline void serialize(Archive& a, tools::wallet2::reserve_proof_entry& x, const boost::serialization::version_type ver)
+ {
+ a & x.txid;
+ a & x.index_in_tx;
+ a & x.shared_secret;
+ a & x.key_image;
+ a & x.shared_secret_sig;
+ a & x.key_image_sig;
+ }
+
+ template <class Archive>
inline void serialize(Archive &a, tools::wallet2::unsigned_tx_set &x, const boost::serialization::version_type ver)
{
a & x.txes;
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index 234c22d85..023b53f28 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -60,6 +60,7 @@ namespace tools
// file_save_error
// invalid_password
// invalid_priority
+ // invalid_multisig_seed
// refresh_error *
// acc_outs_lookup_error
// block_parse_error
@@ -266,6 +267,16 @@ namespace tools
std::string to_string() const { return wallet_logic_error::to_string(); }
};
+ struct invalid_multisig_seed : public wallet_logic_error
+ {
+ explicit invalid_multisig_seed(std::string&& loc)
+ : wallet_logic_error(std::move(loc), "invalid multisig seed")
+ {
+ }
+
+ std::string to_string() const { return wallet_logic_error::to_string(); }
+ };
+
//----------------------------------------------------------------------------------------------------
struct invalid_pregenerated_random : public wallet_logic_error
{
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index f031b765d..3bb69f2be 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -89,6 +89,8 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
wallet_rpc_server::~wallet_rpc_server()
{
+ if (m_wallet)
+ delete m_wallet;
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::set_wallet(wallet2 *cr)
@@ -229,8 +231,9 @@ namespace tools
m_http_client.set_server(walvars->get_daemon_address(), walvars->get_daemon_login());
m_net_server.set_threads_prefix("RPC");
+ auto rng = [](size_t len, uint8_t *ptr) { return crypto::rand(len, ptr); };
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
- std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
+ rng, std::move(bind_port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -255,6 +258,7 @@ namespace tools
entry.note = m_wallet->get_tx_note(pd.m_tx_hash);
entry.type = "in";
entry.subaddr_index = pd.m_subaddr_index;
+ entry.address = m_wallet->get_subaddress_as_str(pd.m_subaddr_index);
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::confirmed_transfer_details &pd)
@@ -280,6 +284,7 @@ namespace tools
entry.type = "out";
entry.subaddr_index = { pd.m_subaddr_account, 0 };
+ entry.address = m_wallet->get_subaddress_as_str({pd.m_subaddr_account, 0});
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &txid, const tools::wallet2::unconfirmed_transfer_details &pd)
@@ -298,6 +303,7 @@ namespace tools
entry.note = m_wallet->get_tx_note(txid);
entry.type = is_failed ? "failed" : "pending";
entry.subaddr_index = { pd.m_subaddr_account, 0 };
+ entry.address = m_wallet->get_subaddress_as_str({pd.m_subaddr_account, 0});
}
//------------------------------------------------------------------------------------------------------------------------------
void wallet_rpc_server::fill_transfer_entry(tools::wallet_rpc::transfer_entry &entry, const crypto::hash &payment_id, const tools::wallet2::pool_payment_details &ppd)
@@ -316,6 +322,7 @@ namespace tools
entry.double_spend_seen = ppd.m_double_spend_seen;
entry.type = "pool";
entry.subaddr_index = pd.m_subaddr_index;
+ entry.address = m_wallet->get_subaddress_as_str(pd.m_subaddr_index);
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er)
@@ -662,7 +669,98 @@ namespace tools
}
return true;
}
+ //------------------------------------------------------------------------------------------------------------------------------
+ static std::string ptx_to_string(const tools::wallet2::pending_tx &ptx)
+ {
+ std::ostringstream oss;
+ boost::archive::portable_binary_oarchive ar(oss);
+ try
+ {
+ ar << ptx;
+ }
+ catch (...)
+ {
+ return "";
+ }
+ return epee::string_tools::buff_to_hex_nodelimer(oss.str());
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ template<typename T> static bool is_error_value(const T &val) { return false; }
+ static bool is_error_value(const std::string &s) { return s.empty(); }
+ //------------------------------------------------------------------------------------------------------------------------------
+ template<typename T, typename V>
+ static bool fill(T &where, V s)
+ {
+ if (is_error_value(s)) return false;
+ where = std::move(s);
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ template<typename T, typename V>
+ static bool fill(std::list<T> &where, V s)
+ {
+ if (is_error_value(s)) return false;
+ where.emplace_back(std::move(s));
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ static uint64_t total_amount(const tools::wallet2::pending_tx &ptx)
+ {
+ uint64_t amount = 0;
+ for (const auto &dest: ptx.dests) amount += dest.amount;
+ return amount;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ template<typename Ts, typename Tu>
+ bool wallet_rpc_server::fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector,
+ bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, bool do_not_relay,
+ Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, epee::json_rpc::error &er)
+ {
+ for (const auto & ptx : ptx_vector)
+ {
+ if (get_tx_key)
+ {
+ std::string s = epee::string_tools::pod_to_hex(ptx.tx_key);
+ for (const crypto::secret_key& additional_tx_key : ptx.additional_tx_keys)
+ s += epee::string_tools::pod_to_hex(additional_tx_key);
+ fill(tx_key, s);
+ }
+ // Compute amount leaving wallet in tx. By convention dests does not include change outputs
+ fill(amount, total_amount(ptx));
+ fill(fee, ptx.fee);
+ }
+ if (m_wallet->multisig())
+ {
+ multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector));
+ if (multisig_txset.empty())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to save multisig tx set after creation";
+ return false;
+ }
+ }
+ else
+ {
+ if (!do_not_relay)
+ m_wallet->commit_tx(ptx_vector);
+
+ // populate response with tx hashes
+ for (auto & ptx : ptx_vector)
+ {
+ bool r = fill(tx_hash, epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
+ r = r && (!get_tx_hex || fill(tx_blob, epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx))));
+ r = r && (!get_tx_metadata || fill(tx_metadata, ptx_to_string(ptx)));
+ if (!r)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Failed to save tx info";
+ return false;
+ }
+ }
+ }
+ return true;
+ }
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er)
{
@@ -705,55 +803,8 @@ namespace tools
return false;
}
- if (req.get_tx_key)
- {
- res.tx_key = epee::string_tools::pod_to_hex(ptx_vector.back().tx_key);
- for (const crypto::secret_key& additional_tx_key : ptx_vector.back().additional_tx_keys)
- res.tx_key += epee::string_tools::pod_to_hex(additional_tx_key);
- }
- res.fee = ptx_vector.back().fee;
-
- if (m_wallet->multisig())
- {
- res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector));
- if (res.multisig_txset.empty())
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- }
- else
- {
- if (!req.do_not_relay)
- m_wallet->commit_tx(ptx_vector);
-
- // populate response with tx hash
- res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx_vector.back().tx));
- if (req.get_tx_hex)
- {
- cryptonote::blobdata blob;
- tx_to_blob(ptx_vector.back().tx, blob);
- res.tx_blob = epee::string_tools::buff_to_hex_nodelimer(blob);
- }
- if (req.get_tx_metadata)
- {
- std::ostringstream oss;
- boost::archive::portable_binary_oarchive ar(oss);
- try
- {
- ar << ptx_vector.back();
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- res.tx_metadata = epee::string_tools::buff_to_hex_nodelimer(oss.str());
- }
- }
- return true;
+ return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, req.do_not_relay,
+ res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
}
catch (const std::exception& e)
{
@@ -786,82 +837,12 @@ namespace tools
try
{
uint64_t mixin = m_wallet->adjust_mixin(req.mixin);
- uint64_t ptx_amount;
- std::vector<wallet2::pending_tx> ptx_vector;
LOG_PRINT_L2("on_transfer_split calling create_transactions_2");
- ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
+ std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
- // populate response with tx hashes
- for (const auto & ptx : ptx_vector)
- {
- if (req.get_tx_keys)
- {
- res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
- for (const crypto::secret_key& additional_tx_key : ptx.additional_tx_keys)
- res.tx_key_list.back() += epee::string_tools::pod_to_hex(additional_tx_key);
- }
- // Compute amount leaving wallet in tx. By convention dests does not include change outputs
- ptx_amount = 0;
- for(auto & dt: ptx.dests)
- ptx_amount += dt.amount;
- res.amount_list.push_back(ptx_amount);
-
- res.fee_list.push_back(ptx.fee);
- }
-
- if (m_wallet->multisig())
- {
- res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector));
- if (res.multisig_txset.empty())
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- }
-
- // populate response with tx hashes
- for (const auto & ptx : ptx_vector)
- {
- if (!req.do_not_relay)
- {
- LOG_PRINT_L2("on_transfer_split calling commit_tx");
- m_wallet->commit_tx(ptx_vector);
- LOG_PRINT_L2("on_transfer_split called commit_tx");
- }
-
- // populate response with tx hashes
- for (auto & ptx : ptx_vector)
- {
- res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
-
- if (req.get_tx_hex)
- {
- cryptonote::blobdata blob;
- tx_to_blob(ptx.tx, blob);
- res.tx_blob_list.push_back(epee::string_tools::buff_to_hex_nodelimer(blob));
- }
- if (req.get_tx_metadata)
- {
- std::ostringstream oss;
- boost::archive::portable_binary_oarchive ar(oss);
- try
- {
- ar << ptx;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
- }
- }
- }
-
- return true;
+ return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay,
+ res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
}
catch (const std::exception& e)
{
@@ -885,69 +866,8 @@ namespace tools
{
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
- for (const auto & ptx : ptx_vector)
- {
- if (req.get_tx_keys)
- {
- res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
- }
- res.fee_list.push_back(ptx.fee);
- }
-
- if (m_wallet->multisig())
- {
- for (tools::wallet2::pending_tx &ptx: ptx_vector)
- {
- std::ostringstream oss;
- boost::archive::portable_binary_oarchive ar(oss);
- try
- {
- ar << ptx;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- res.multisig_txset.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
- }
- }
- else
- {
- if (!req.do_not_relay)
- m_wallet->commit_tx(ptx_vector);
-
- // populate response with tx hashes
- for (auto & ptx : ptx_vector)
- {
- res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
- if (req.get_tx_hex)
- {
- cryptonote::blobdata blob;
- tx_to_blob(ptx.tx, blob);
- res.tx_blob_list.push_back(epee::string_tools::buff_to_hex_nodelimer(blob));
- }
- if (req.get_tx_metadata)
- {
- std::ostringstream oss;
- boost::archive::portable_binary_oarchive ar(oss);
- try
- {
- ar << ptx;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
- }
- }
- }
-
- return true;
+ return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay,
+ res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
}
catch (const std::exception& e)
{
@@ -985,68 +905,8 @@ namespace tools
uint64_t mixin = m_wallet->adjust_mixin(req.mixin);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
- for (const auto & ptx : ptx_vector)
- {
- if (req.get_tx_keys)
- {
- res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
- }
- }
-
- if (m_wallet->multisig())
- {
- for (tools::wallet2::pending_tx &ptx: ptx_vector)
- {
- std::ostringstream oss;
- boost::archive::portable_binary_oarchive ar(oss);
- try
- {
- ar << ptx;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- res.multisig_txset.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
- }
- }
- else
- {
- if (!req.do_not_relay)
- m_wallet->commit_tx(ptx_vector);
-
- // populate response with tx hashes
- for (auto & ptx : ptx_vector)
- {
- res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
- if (req.get_tx_hex)
- {
- cryptonote::blobdata blob;
- tx_to_blob(ptx.tx, blob);
- res.tx_blob_list.push_back(epee::string_tools::buff_to_hex_nodelimer(blob));
- }
- if (req.get_tx_metadata)
- {
- std::ostringstream oss;
- boost::archive::portable_binary_oarchive ar(oss);
- try
- {
- ar << ptx;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
- }
- }
- }
-
- return true;
+ return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay,
+ res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
}
catch (const std::exception& e)
{
@@ -1112,63 +972,12 @@ namespace tools
return false;
}
- if (req.get_tx_key)
- {
- res.tx_key = epee::string_tools::pod_to_hex(ptx.tx_key);
- }
-
- if (m_wallet->multisig())
- {
- res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector));
- if (res.multisig_txset.empty())
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- }
- else
- {
- if (!req.do_not_relay)
- m_wallet->commit_tx(ptx_vector);
-
- // populate response with tx hashes
- res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx));
- if (req.get_tx_hex)
- {
- cryptonote::blobdata blob;
- tx_to_blob(ptx.tx, blob);
- res.tx_blob = epee::string_tools::buff_to_hex_nodelimer(blob);
- }
- if (req.get_tx_metadata)
- {
- std::ostringstream oss;
- boost::archive::portable_binary_oarchive ar(oss);
- try
- {
- ar << ptx;
- }
- catch (...)
- {
- er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
- er.message = "Failed to save multisig tx set after creation";
- return false;
- }
- res.tx_metadata = epee::string_tools::buff_to_hex_nodelimer(oss.str());
- }
- }
- return true;
- }
- catch (const tools::error::daemon_busy& e)
- {
- er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY;
- er.message = e.what();
- return false;
+ return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, req.do_not_relay,
+ res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
}
catch (const std::exception& e)
{
- er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR;
- er.message = e.what();
+ handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR);
return false;
}
catch (...)
@@ -1916,6 +1725,66 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_get_reserve_proof(const wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF::response& res, epee::json_rpc::error& er)
+ {
+ if (!m_wallet) return not_open(er);
+
+ boost::optional<std::pair<uint32_t, uint64_t>> account_minreserve;
+ if (!req.all)
+ {
+ if (req.account_index >= m_wallet->get_num_subaddress_accounts())
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Account index is out of bound";
+ return false;
+ }
+ account_minreserve = std::make_pair(req.account_index, req.amount);
+ }
+
+ try
+ {
+ res.signature = m_wallet->get_reserve_proof(account_minreserve, req.message);
+ }
+ catch (const std::exception &e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = e.what();
+ return false;
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
+ bool wallet_rpc_server::on_check_reserve_proof(const wallet_rpc::COMMAND_RPC_CHECK_RESERVE_PROOF::request& req, wallet_rpc::COMMAND_RPC_CHECK_RESERVE_PROOF::response& res, epee::json_rpc::error& er)
+ {
+ if (!m_wallet) return not_open(er);
+
+ cryptonote::address_parse_info info;
+ if (!get_account_address_from_str(info, m_wallet->testnet(), req.address))
+ {
+ er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
+ er.message = "Invalid address";
+ return false;
+ }
+ if (info.is_subaddress)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = "Address must not be a subaddress";
+ return false;
+ }
+
+ try
+ {
+ res.good = m_wallet->check_reserve_proof(info.address, req.message, req.signature, res.total, res.spent);
+ }
+ catch (const std::exception &e)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
+ er.message = e.what();
+ return false;
+ }
+ return true;
+ }
+ //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index b20198b78..9e2e9d216 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -104,6 +104,8 @@ namespace tools
MAP_JON_RPC_WE("check_tx_proof", on_check_tx_proof, wallet_rpc::COMMAND_RPC_CHECK_TX_PROOF)
MAP_JON_RPC_WE("get_spend_proof", on_get_spend_proof, wallet_rpc::COMMAND_RPC_GET_SPEND_PROOF)
MAP_JON_RPC_WE("check_spend_proof", on_check_spend_proof, wallet_rpc::COMMAND_RPC_CHECK_SPEND_PROOF)
+ MAP_JON_RPC_WE("get_reserve_proof", on_get_reserve_proof, wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF)
+ MAP_JON_RPC_WE("check_reserve_proof", on_check_reserve_proof, wallet_rpc::COMMAND_RPC_CHECK_RESERVE_PROOF)
MAP_JON_RPC_WE("get_transfers", on_get_transfers, wallet_rpc::COMMAND_RPC_GET_TRANSFERS)
MAP_JON_RPC_WE("get_transfer_by_txid", on_get_transfer_by_txid, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID)
MAP_JON_RPC_WE("sign", on_sign, wallet_rpc::COMMAND_RPC_SIGN)
@@ -170,6 +172,8 @@ namespace tools
bool on_check_tx_proof(const wallet_rpc::COMMAND_RPC_CHECK_TX_PROOF::request& req, wallet_rpc::COMMAND_RPC_CHECK_TX_PROOF::response& res, epee::json_rpc::error& er);
bool on_get_spend_proof(const wallet_rpc::COMMAND_RPC_GET_SPEND_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_SPEND_PROOF::response& res, epee::json_rpc::error& er);
bool on_check_spend_proof(const wallet_rpc::COMMAND_RPC_CHECK_SPEND_PROOF::request& req, wallet_rpc::COMMAND_RPC_CHECK_SPEND_PROOF::response& res, epee::json_rpc::error& er);
+ bool on_get_reserve_proof(const wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF::request& req, wallet_rpc::COMMAND_RPC_GET_RESERVE_PROOF::response& res, epee::json_rpc::error& er);
+ bool on_check_reserve_proof(const wallet_rpc::COMMAND_RPC_CHECK_RESERVE_PROOF::request& req, wallet_rpc::COMMAND_RPC_CHECK_RESERVE_PROOF::response& res, epee::json_rpc::error& er);
bool on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res, epee::json_rpc::error& er);
bool on_get_transfer_by_txid(const wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFER_BY_TXID::response& res, epee::json_rpc::error& er);
bool on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er);
@@ -207,6 +211,11 @@ namespace tools
bool not_open(epee::json_rpc::error& er);
void handle_rpc_exception(const std::exception_ptr& e, epee::json_rpc::error& er, int default_error_code);
+ template<typename Ts, typename Tu>
+ bool fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector,
+ bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, bool do_not_relay,
+ Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, epee::json_rpc::error &er);
+
wallet2 *m_wallet;
std::string m_wallet_dir;
tools::private_file rpc_login_file;
diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h
index 76c02039b..ac25e8e84 100644
--- a/src/wallet/wallet_rpc_server_commands_defs.h
+++ b/src/wallet/wallet_rpc_server_commands_defs.h
@@ -411,6 +411,7 @@ namespace wallet_rpc
std::string tx_hash;
std::string tx_key;
std::list<std::string> amount_keys;
+ uint64_t amount;
uint64_t fee;
std::string tx_blob;
std::string tx_metadata;
@@ -420,6 +421,7 @@ namespace wallet_rpc
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(tx_key)
KV_SERIALIZE(amount_keys)
+ KV_SERIALIZE(amount)
KV_SERIALIZE(fee)
KV_SERIALIZE(tx_blob)
KV_SERIALIZE(tx_metadata)
@@ -520,14 +522,16 @@ namespace wallet_rpc
{
std::list<std::string> tx_hash_list;
std::list<std::string> tx_key_list;
+ std::list<uint64_t> amount_list;
std::list<uint64_t> fee_list;
std::list<std::string> tx_blob_list;
std::list<std::string> tx_metadata_list;
- std::list<std::string> multisig_txset;
+ std::string multisig_txset;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash_list)
KV_SERIALIZE(tx_key_list)
+ KV_SERIALIZE(amount_list)
KV_SERIALIZE(fee_list)
KV_SERIALIZE(tx_blob_list)
KV_SERIALIZE(tx_metadata_list)
@@ -582,14 +586,16 @@ namespace wallet_rpc
{
std::list<std::string> tx_hash_list;
std::list<std::string> tx_key_list;
+ std::list<uint64_t> amount_list;
std::list<uint64_t> fee_list;
std::list<std::string> tx_blob_list;
std::list<std::string> tx_metadata_list;
- std::list<std::string> multisig_txset;
+ std::string multisig_txset;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash_list)
KV_SERIALIZE(tx_key_list)
+ KV_SERIALIZE(amount_list)
KV_SERIALIZE(fee_list)
KV_SERIALIZE(tx_blob_list)
KV_SERIALIZE(tx_metadata_list)
@@ -631,6 +637,7 @@ namespace wallet_rpc
{
std::string tx_hash;
std::string tx_key;
+ uint64_t amount;
uint64_t fee;
std::string tx_blob;
std::string tx_metadata;
@@ -639,6 +646,7 @@ namespace wallet_rpc
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(tx_hash)
KV_SERIALIZE(tx_key)
+ KV_SERIALIZE(amount)
KV_SERIALIZE(fee)
KV_SERIALIZE(tx_blob)
KV_SERIALIZE(tx_metadata)
@@ -1106,6 +1114,7 @@ namespace wallet_rpc
std::string type;
uint64_t unlock_time;
cryptonote::subaddress_index subaddr_index;
+ std::string address;
bool double_spend_seen;
BEGIN_KV_SERIALIZE_MAP()
@@ -1120,6 +1129,7 @@ namespace wallet_rpc
KV_SERIALIZE(type);
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(subaddr_index);
+ KV_SERIALIZE(address);
KV_SERIALIZE(double_spend_seen)
END_KV_SERIALIZE_MAP()
};
@@ -1172,6 +1182,62 @@ namespace wallet_rpc
};
};
+ struct COMMAND_RPC_GET_RESERVE_PROOF
+ {
+ struct request
+ {
+ bool all;
+ uint32_t account_index; // ignored when `all` is true
+ uint64_t amount; // ignored when `all` is true
+ std::string message;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(all)
+ KV_SERIALIZE(account_index)
+ KV_SERIALIZE(amount)
+ KV_SERIALIZE(message)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ std::string signature;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(signature)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
+ struct COMMAND_RPC_CHECK_RESERVE_PROOF
+ {
+ struct request
+ {
+ std::string address;
+ std::string message;
+ std::string signature;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(address)
+ KV_SERIALIZE(message)
+ KV_SERIALIZE(signature)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct response
+ {
+ bool good;
+ uint64_t total;
+ uint64_t spent;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(good)
+ KV_SERIALIZE(total)
+ KV_SERIALIZE(spent)
+ END_KV_SERIALIZE_MAP()
+ };
+ };
+
struct COMMAND_RPC_GET_TRANSFERS
{
struct request
diff --git a/tests/fuzz/cold-outputs.cpp b/tests/fuzz/cold-outputs.cpp
index 2785db05d..6e813d823 100644
--- a/tests/fuzz/cold-outputs.cpp
+++ b/tests/fuzz/cold-outputs.cpp
@@ -53,16 +53,8 @@ int ColdOutputsFuzzer::init()
try
{
- boost::filesystem::remove("/tmp/cold-outputs-test.keys");
- boost::filesystem::remove("/tmp/cold-outputs-test.address.txt");
- boost::filesystem::remove("/tmp/cold-outputs-test");
-
wallet.init("");
- wallet.generate("/tmp/cold-outputs-test", "", spendkey, true, false);
-
- boost::filesystem::remove("/tmp/cold-outputs-test.keys");
- boost::filesystem::remove("/tmp/cold-outputs-test.address.txt");
- boost::filesystem::remove("/tmp/cold-outputs-test");
+ wallet.generate("", "", spendkey, true, false);
}
catch (const std::exception &e)
{
diff --git a/tests/fuzz/cold-transaction.cpp b/tests/fuzz/cold-transaction.cpp
index f0b4b26d6..20715c9ed 100644
--- a/tests/fuzz/cold-transaction.cpp
+++ b/tests/fuzz/cold-transaction.cpp
@@ -54,16 +54,8 @@ int ColdTransactionFuzzer::init()
try
{
- boost::filesystem::remove("/tmp/cold-transaction-test.keys");
- boost::filesystem::remove("/tmp/cold-transaction-test.address.txt");
- boost::filesystem::remove("/tmp/cold-transaction-test");
-
wallet.init("");
- wallet.generate("/tmp/cold-transaction-test", "", spendkey, true, false);
-
- boost::filesystem::remove("/tmp/cold-transaction-test.keys");
- boost::filesystem::remove("/tmp/cold-transaction-test.address.txt");
- boost::filesystem::remove("/tmp/cold-transaction-test");
+ wallet.generate("", "", spendkey, true, false);
}
catch (const std::exception &e)
{
diff --git a/tests/fuzz/signature.cpp b/tests/fuzz/signature.cpp
index 7ec4434e6..e7a0a53df 100644
--- a/tests/fuzz/signature.cpp
+++ b/tests/fuzz/signature.cpp
@@ -54,16 +54,8 @@ int SignatureFuzzer::init()
try
{
- boost::filesystem::remove("/tmp/signature-test.keys");
- boost::filesystem::remove("/tmp/signature-test.address.txt");
- boost::filesystem::remove("/tmp/signature-test");
-
wallet.init("");
- wallet.generate("/tmp/signature-test", "", spendkey, true, false);
-
- boost::filesystem::remove("/tmp/signature-test.keys");
- boost::filesystem::remove("/tmp/signature-test.address.txt");
- boost::filesystem::remove("/tmp/signature-test");
+ wallet.generate("", "", spendkey, true, false);
cryptonote::address_parse_info info;
if (!cryptonote::get_account_address_from_str_or_url(info, true, "9uVsvEryzpN8WH2t1WWhFFCG5tS8cBNdmJYNRuckLENFimfauV5pZKeS1P2CbxGkSDTUPHXWwiYE5ZGSXDAGbaZgDxobqDN"))
diff --git a/tests/gtest/cmake/internal_utils.cmake b/tests/gtest/cmake/internal_utils.cmake
index 93e6dbb7c..364db5970 100644
--- a/tests/gtest/cmake/internal_utils.cmake
+++ b/tests/gtest/cmake/internal_utils.cmake
@@ -87,7 +87,7 @@ macro(config_compiler_and_linker)
set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0")
set(cxx_no_rtti_flags "-GR-")
elseif (CMAKE_COMPILER_IS_GNUCXX)
- set(cxx_base_flags "-Wall -Wshadow")
+ set(cxx_base_flags "-Wall -Wshadow -fPIC")
set(cxx_exception_flags "-fexceptions")
set(cxx_no_exception_flags "-fno-exceptions")
# Until version 4.3.2, GCC doesn't define a macro to indicate
diff --git a/tests/performance_tests/CMakeLists.txt b/tests/performance_tests/CMakeLists.txt
index 2b3a0d6f8..1a0677925 100644
--- a/tests/performance_tests/CMakeLists.txt
+++ b/tests/performance_tests/CMakeLists.txt
@@ -41,6 +41,7 @@ set(performance_tests_headers
generate_key_image_helper.h
generate_keypair.h
is_out_to_acc.h
+ subaddress_expand.h
multi_tx_test_base.h
performance_tests.h
performance_utils.h
@@ -51,6 +52,7 @@ add_executable(performance_tests
${performance_tests_headers})
target_link_libraries(performance_tests
PRIVATE
+ wallet
cryptonote_core
common
cncrypto
diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp
index 459eecba4..2f3ce289d 100644
--- a/tests/performance_tests/main.cpp
+++ b/tests/performance_tests/main.cpp
@@ -44,6 +44,7 @@
#include "generate_key_image_helper.h"
#include "generate_keypair.h"
#include "is_out_to_acc.h"
+#include "subaddress_expand.h"
#include "sc_reduce32.h"
#include "cn_fast_hash.h"
@@ -112,6 +113,8 @@ int main(int argc, char** argv)
TEST_PERFORMANCE0(test_generate_keypair);
TEST_PERFORMANCE0(test_sc_reduce32);
+ TEST_PERFORMANCE2(test_wallet2_expand_subaddresses, 50, 200);
+
TEST_PERFORMANCE0(test_cn_slow_hash);
TEST_PERFORMANCE1(test_cn_fast_hash, 32);
TEST_PERFORMANCE1(test_cn_fast_hash, 16384);
diff --git a/tests/performance_tests/subaddress_expand.h b/tests/performance_tests/subaddress_expand.h
new file mode 100644
index 000000000..fea92d54b
--- /dev/null
+++ b/tests/performance_tests/subaddress_expand.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2017, 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.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include "wallet/wallet2.h"
+#include "ringct/rctOps.h"
+
+#include "single_tx_test_base.h"
+
+template<size_t Major, size_t Minor>
+class test_wallet2_expand_subaddresses : public single_tx_test_base
+{
+public:
+ static const size_t loop_count = 1;
+ static const size_t major = Major;
+ static const size_t minor = Minor;
+
+ bool init()
+ {
+ if (!single_tx_test_base::init())
+ return false;
+ wallet.set_subaddress_lookahead(1, 1);
+ crypto::secret_key spendkey = rct::rct2sk(rct::skGen());
+ wallet.generate("", "", spendkey, true, false);
+ wallet.set_subaddress_lookahead(major, minor);
+ return true;
+ }
+
+ bool test()
+ {
+ wallet.expand_subaddresses({0, 0});
+ return true;
+ }
+
+private:
+ tools::wallet2 wallet;
+};
diff --git a/tests/unit_tests/crypto.cpp b/tests/unit_tests/crypto.cpp
index d9a7b8ad5..3a8e787ec 100644
--- a/tests/unit_tests/crypto.cpp
+++ b/tests/unit_tests/crypto.cpp
@@ -47,14 +47,6 @@ namespace
"8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"
"6c7251d54154cfa92c173a0dd39c1f948b655970153799af2aeadc9ff1add0ea";
- static std::uint8_t md[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00
- };
-
template<typename T>
bool is_formatted()
{
@@ -69,22 +61,6 @@ namespace
out << "BEGIN" << value << "END";
return out.str() == "BEGIN<" + std::string{expected, sizeof(T) * 2} + ">END";
}
-
- bool keccak_harness()
- {
- size_t inlen = sizeof(source);
- int mdlen = (int)sizeof(md);
- keccak(source, inlen, md, mdlen);
-
- if (md[0] != 0x00)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
}
TEST(Crypto, Ostream)
diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp
index c235f49fd..0a472a421 100644
--- a/tests/unit_tests/hardfork.cpp
+++ b/tests/unit_tests/hardfork.cpp
@@ -118,7 +118,7 @@ public:
virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const { return 0; }
virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; }
virtual void remove_txpool_tx(const crypto::hash& txid) {}
- virtual txpool_tx_meta_t get_txpool_tx_meta(const crypto::hash& txid) const { return txpool_tx_meta_t(); }
+ virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { return false; }
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; }
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; }
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = false) const { return false; }
diff --git a/tests/unit_tests/http.cpp b/tests/unit_tests/http.cpp
index 5e427f064..0e8f9f747 100644
--- a/tests/unit_tests/http.cpp
+++ b/tests/unit_tests/http.cpp
@@ -60,12 +60,18 @@
#include "md5_l.h"
#include "string_tools.h"
+#include "crypto/crypto.h"
namespace {
namespace http = epee::net_utils::http;
using fields = std::unordered_map<std::string, std::string>;
using auth_responses = std::vector<fields>;
+void rng(size_t len, uint8_t *ptr)
+{
+ crypto::rand(len, ptr);
+}
+
std::string quoted(std::string str)
{
str.insert(str.begin(), '"');
@@ -250,13 +256,13 @@ std::string get_nc(std::uint32_t count)
TEST(HTTP_Server_Auth, NotRequired)
{
- http::http_server_auth auth{};
+ http::http_server_auth auth{}; // no rng here
EXPECT_FALSE(auth.get_response(http::http_request_info{}));
}
TEST(HTTP_Server_Auth, MissingAuth)
{
- http::http_server_auth auth{{"foo", "bar"}};
+ http::http_server_auth auth{{"foo", "bar"}, rng};
EXPECT_TRUE(bool(auth.get_response(http::http_request_info{})));
{
http::http_request_info request{};
@@ -267,7 +273,7 @@ TEST(HTTP_Server_Auth, MissingAuth)
TEST(HTTP_Server_Auth, BadSyntax)
{
- http::http_server_auth auth{{"foo", "bar"}};
+ http::http_server_auth auth{{"foo", "bar"}, rng};
EXPECT_TRUE(bool(auth.get_response(make_request({{u8"algorithm", "fo\xFF"}}))));
EXPECT_TRUE(bool(auth.get_response(make_request({{u8"cnonce", "\"000\xFF\""}}))));
EXPECT_TRUE(bool(auth.get_response(make_request({{u8"cnonce \xFF =", "\"000\xFF\""}}))));
@@ -277,7 +283,7 @@ TEST(HTTP_Server_Auth, BadSyntax)
TEST(HTTP_Server_Auth, MD5)
{
http::login user{"foo", "bar"};
- http::http_server_auth auth{user};
+ http::http_server_auth auth{user, rng};
const auto response = auth.get_response(make_request(fields{}));
ASSERT_TRUE(bool(response));
@@ -326,7 +332,7 @@ TEST(HTTP_Server_Auth, MD5_sess)
constexpr const char cnonce[] = "not a good cnonce";
http::login user{"foo", "bar"};
- http::http_server_auth auth{user};
+ http::http_server_auth auth{user, rng};
const auto response = auth.get_response(make_request(fields{}));
ASSERT_TRUE(bool(response));
@@ -378,7 +384,7 @@ TEST(HTTP_Server_Auth, MD5_auth)
constexpr const char qop[] = "auth";
http::login user{"foo", "bar"};
- http::http_server_auth auth{user};
+ http::http_server_auth auth{user, rng};
const auto response = auth.get_response(make_request(fields{}));
ASSERT_TRUE(bool(response));
@@ -446,7 +452,7 @@ TEST(HTTP_Server_Auth, MD5_sess_auth)
constexpr const char qop[] = "auth";
http::login user{"foo", "bar"};
- http::http_server_auth auth{user};
+ http::http_server_auth auth{user, rng};
const auto response = auth.get_response(make_request(fields{}));
ASSERT_TRUE(bool(response));
@@ -523,7 +529,7 @@ TEST(HTTP_Auth, DogFood)
const http::login user{"some_user", "ultimate password"};
- http::http_server_auth server{user};
+ http::http_server_auth server{user, rng};
http::http_client_auth client{user};
http::http_request_info request{};
diff --git a/tests/unit_tests/memwipe.cpp b/tests/unit_tests/memwipe.cpp
index 2d8980ef7..59f50cef8 100644
--- a/tests/unit_tests/memwipe.cpp
+++ b/tests/unit_tests/memwipe.cpp
@@ -30,7 +30,7 @@
#include <stdint.h>
#include "misc_log_ex.h"
-#include "common/memwipe.h"
+#include "memwipe.h"
// Probably won't catch the optimized out case, but at least we test
// it works in the normal case
diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp
index 2ef1097da..8a75ac435 100644
--- a/tests/unit_tests/serialization.cpp
+++ b/tests/unit_tests/serialization.cpp
@@ -38,7 +38,6 @@
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "ringct/rctSigs.h"
-#include "serialization/serialization.h"
#include "serialization/binary_archive.h"
#include "serialization/json_archive.h"
#include "serialization/debug_archive.h"
diff --git a/tests/unit_tests/subaddress.cpp b/tests/unit_tests/subaddress.cpp
index c304b7347..ca950b25d 100644
--- a/tests/unit_tests/subaddress.cpp
+++ b/tests/unit_tests/subaddress.cpp
@@ -44,7 +44,7 @@ class WalletSubaddress : public ::testing::Test
{
try
{
- w1.generate(wallet_name, password, recovery_key, true, false);
+ w1.generate("", password, recovery_key, true, false);
}
catch (const std::exception& e)
{
@@ -58,24 +58,9 @@ class WalletSubaddress : public ::testing::Test
virtual void TearDown()
{
- boost::filesystem::wpath wallet_file(wallet_name);
- boost::filesystem::wpath wallet_address_file(wallet_name + ".address.txt");
- boost::filesystem::wpath wallet_keys_file(wallet_name + ".keys");
-
- if ( boost::filesystem::exists(wallet_file) )
- boost::filesystem::remove(wallet_file);
-
- if ( boost::filesystem::exists(wallet_address_file) )
- boost::filesystem::remove(wallet_address_file);
-
- if ( boost::filesystem::exists(wallet_keys_file) )
- boost::filesystem::remove(wallet_keys_file);
}
tools::wallet2 w1;
- std::string path_working_dir = ".";
- std::string path_test_wallet = "test_wallet";
- const std::string wallet_name = path_working_dir + "/" + path_test_wallet;
const std::string password = "testpass";
crypto::secret_key recovery_key = crypto::secret_key();
const std::string test_label = "subaddress test label";
diff --git a/tests/unit_tests/varint.cpp b/tests/unit_tests/varint.cpp
index 2b31cdfdf..577ad4d26 100644
--- a/tests/unit_tests/varint.cpp
+++ b/tests/unit_tests/varint.cpp
@@ -36,7 +36,6 @@
#include <boost/foreach.hpp>
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/cryptonote_basic_impl.h"
-#include "serialization/serialization.h"
#include "serialization/binary_archive.h"
#include "serialization/json_archive.h"
#include "serialization/debug_archive.h"
diff --git a/translations/CMakeLists.txt b/translations/CMakeLists.txt
new file mode 100644
index 000000000..a069daea9
--- /dev/null
+++ b/translations/CMakeLists.txt
@@ -0,0 +1,63 @@
+# Copyright (c) 2017, 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.
+
+cmake_minimum_required(VERSION 2.8.7)
+
+project(translations)
+
+add_executable(generate_translations_header generate_translations_header.c)
+
+find_program(LRELEASE lrelease)
+if(LRELEASE STREQUAL "LRELEASE-NOTFOUND")
+ set(ts_files "")
+ message(WARNING "lrelease program not found, translation files not built")
+else()
+ execute_process(COMMAND ${LRELEASE} -version
+ RESULT_VARIABLE lrelease_ret)
+ if(NOT lrelease_ret EQUAL "0")
+ set(ts_files "")
+ message(WARNING "lrelease program not working, translation files not built")
+ else()
+ file(GLOB ts_files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" *.ts)
+ foreach(ts_file ${ts_files})
+ string(REPLACE ".ts" ".qm" qm_file "${ts_file}")
+ add_custom_command(TARGET generate_translations_header
+ PRE_BUILD
+ COMMAND ${LRELEASE} "${CMAKE_CURRENT_SOURCE_DIR}/${ts_file}" -qm "${qm_file}"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BIN_DIR}")
+ endforeach()
+ endif()
+endif()
+
+string(REPLACE ".ts" ".qm" qm_files "${ts_files}")
+
+add_custom_command(TARGET generate_translations_header
+ POST_BUILD
+ COMMAND generate_translations_header ${qm_files}
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BIN_DIR}"
+ COMMENT "Generating embedded translations header")
diff --git a/translations/generate_translations_header.c b/translations/generate_translations_header.c
new file mode 100644
index 000000000..69671913e
--- /dev/null
+++ b/translations/generate_translations_header.c
@@ -0,0 +1,86 @@
+// Copyright (c) 2013, Sergey Lyubka
+// Copyright (c) 2017, The Monero Project
+// All rights reserved.
+// Released under the MIT license.
+
+// This program takes a list of files as an input, and produces C++ code that
+// contains the contents of all these files as a collection of strings.
+//
+// Usage:
+// 1. Compile this file:
+// cc -o generate-translations-header generate-translations-header.c
+//
+// 2. Convert list of files into single header:
+// ./generate-translations-header monero_fr.qm monero_it.qm > translations_files.h
+//
+// 3. In your application code, include translations_files.h, then you can
+// access the files using this function:
+// static bool find_embedded_file(const std::string &file_name, std::string &data);
+// std::string data;
+// find_embedded_file("monero_fr.qm", data);
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static const char *code =
+ "static bool find_embedded_file(const std::string &name, std::string &data) {\n"
+ " const struct embedded_file *p;\n"
+ " for (p = embedded_files; p->name != NULL; p++) {\n"
+ " if (*p->name == name) {\n"
+ " data = *p->data;\n"
+ " return true;\n"
+ " }\n"
+ " }\n"
+ " return false;\n"
+ "}\n";
+
+int main(int argc, char *argv[]) {
+ FILE *fp, *foutput;
+ int i, j, ch;
+
+ if((foutput = fopen("translation_files.h", "w")) == NULL) {
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(foutput, "#ifndef TRANSLATION_FILES_H\n");
+ fprintf(foutput, "#define TRANSLATION_FILES_H\n\n");
+ fprintf(foutput, "#include <string>\n\n");
+
+ for (i = 1; i < argc; i++) {
+ if ((fp = fopen(argv[i], "rb")) == NULL) {
+ exit(EXIT_FAILURE);
+ } else {
+ fprintf(foutput, "static const std::string translation_file_name_%d = \"%s\";\n", i, argv[i]);
+ fprintf(foutput, "static const std::string translation_file_data_%d = std::string(", i);
+ for (j = 0; (ch = fgetc(fp)) != EOF; j++) {
+ if ((j % 16) == 0) {
+ if (j > 0) {
+ fprintf(foutput, "%s", "\"");
+ }
+ fprintf(foutput, "%s", "\n \"");
+ }
+ fprintf(foutput, "\\x%02x", ch);
+ }
+ fprintf(foutput, "\",\n %d);\n\n", j);
+ fclose(fp);
+ }
+ }
+
+ fprintf(foutput, "%s", "static const struct embedded_file {\n");
+ fprintf(foutput, "%s", " const std::string *name;\n");
+ fprintf(foutput, "%s", " const std::string *data;\n");
+ fprintf(foutput, "%s", "} embedded_files[] = {\n");
+
+ for (i = 1; i < argc; i++) {
+ fprintf(foutput, " {&translation_file_name_%d, &translation_file_data_%d},\n", i, i);
+ }
+ fprintf(foutput, "%s", " {NULL, NULL}\n");
+ fprintf(foutput, "%s", "};\n\n");
+ fprintf(foutput, "%s\n", code);
+
+ fprintf(foutput, "#endif /* TRANSLATION_FILES_H */\n");
+
+ fclose(foutput);
+
+ return EXIT_SUCCESS;
+}
diff --git a/translations/monero_sv.ts b/translations/monero_sv.ts
new file mode 100644
index 000000000..0090857c0
--- /dev/null
+++ b/translations/monero_sv.ts
@@ -0,0 +1,2783 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE TS []>
+<TS version="2.1">
+<context>
+ <name>Monero::AddressBookImpl</name>
+ <message>
+ <location filename="../src/wallet/api/address_book.cpp" line="55"/>
+ <source>Invalid destination address</source>
+ <translation>Ogiltig måladress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/address_book.cpp" line="65"/>
+ <source>Invalid payment ID. Short payment ID should only be used in an integrated address</source>
+ <translation>Ogiltigt betalnings-ID. Kort betalnings-ID ska endast användas i en integrerad adress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/address_book.cpp" line="72"/>
+ <source>Invalid payment ID</source>
+ <translation>Ogiltigt betalnings-ID</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/address_book.cpp" line="79"/>
+ <source>Integrated address and long payment id can&apos;t be used at the same time</source>
+ <translation>Integrerad adress och långt betalnings-ID kan inte användas samtidigt</translation>
+ </message>
+</context>
+<context>
+ <name>Monero::PendingTransactionImpl</name>
+ <message>
+ <location filename="../src/wallet/api/pending_transaction.cpp" line="90"/>
+ <source>Attempting to save transaction to file, but specified file(s) exist. Exiting to not risk overwriting. File:</source>
+ <translation>Försöker spara transaktion till fil, men angiven fil finns redan. Avslutar för att inte riskera att skriva över någonting. Fil:</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/pending_transaction.cpp" line="97"/>
+ <source>Failed to write transaction(s) to file</source>
+ <translation>Det gick inte att skriva transaktioner till fil</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/pending_transaction.cpp" line="114"/>
+ <source>daemon is busy. Please try again later.</source>
+ <translation>daemonen är upptagen. Försök igen senare.</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/pending_transaction.cpp" line="117"/>
+ <source>no connection to daemon. Please make sure daemon is running.</source>
+ <translation>ingen anslutning till daemonen. Se till att daemonen körs.</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/pending_transaction.cpp" line="121"/>
+ <source>transaction %s was rejected by daemon with status: </source>
+ <translation>transaktionen %s avvisades av daemonen med status: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/pending_transaction.cpp" line="126"/>
+ <source>. Reason: </source>
+ <translation>. Orsak: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/pending_transaction.cpp" line="128"/>
+ <source>Unknown exception: </source>
+ <translation>Okänt undantag: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/pending_transaction.cpp" line="131"/>
+ <source>Unhandled exception</source>
+ <translation>Ohanterat undantag</translation>
+ </message>
+</context>
+<context>
+ <name>Monero::UnsignedTransactionImpl</name>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="75"/>
+ <source>This is a watch only wallet</source>
+ <translation>Detta är en granskningsplånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="85"/>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="92"/>
+ <source>Failed to sign transaction</source>
+ <translation>Det gick inte att signera transaktionen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="135"/>
+ <source>Claimed change does not go to a paid address</source>
+ <translation>Begärd växel går inte till en betald adress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="141"/>
+ <source>Claimed change is larger than payment to the change address</source>
+ <translation>Begärd växel är större än betalning till växeladressen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="151"/>
+ <source>Change goes to more than one address</source>
+ <translation>Växel går till mer än en adress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="164"/>
+ <source>sending %s to %s</source>
+ <translation>skickar %s till %s</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="170"/>
+ <source>with no destinations</source>
+ <translation>utan några mål</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="176"/>
+ <source>%s change to %s</source>
+ <translation>%s växel till %s</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="179"/>
+ <source>no change</source>
+ <translation>ingen växel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/unsigned_transaction.cpp" line="181"/>
+ <source>Loaded %lu transactions, for %s, fee %s, %s, %s, with min mixin %lu. %s</source>
+ <translation>Läste in %lu transaktioner, för %s, avgift %s, %s, %s, med minsta mixin %lu. %s</translation>
+ </message>
+</context>
+<context>
+ <name>Monero::WalletImpl</name>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="942"/>
+ <source>payment id has invalid format, expected 16 or 64 character hex string: </source>
+ <translation>betalnings-ID har ogiltigt format. En 16- eller 64-teckens hex-sträng förväntades: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="952"/>
+ <source>Failed to add short payment id: </source>
+ <translation>Det gick inte att lägga till kort betalnings-ID: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="978"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1072"/>
+ <source>daemon is busy. Please try again later.</source>
+ <translation>daemonen är upptagen. Försök igen senare.</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="981"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1075"/>
+ <source>no connection to daemon. Please make sure daemon is running.</source>
+ <translation>ingen anslutning till daemonen. Se till att daemonen körs.</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="984"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1078"/>
+ <source>RPC error: </source>
+ <translation>RPC-fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1081"/>
+ <source>failed to get random outputs to mix</source>
+ <translation>det gick inte att hämta slumpmässiga utgångar att mixa</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="994"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1088"/>
+ <source>not enough money to transfer, available only %s, sent amount %s</source>
+ <translation>inte tillräckligt med pengar för överföring, endast tillgängligt %s, skickat belopp %s</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="403"/>
+ <source>failed to parse address</source>
+ <translation>det gick inte att parsa adressen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="415"/>
+ <source>failed to parse secret spend key</source>
+ <translation>det gick inte att parsa hemlig spendernyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="425"/>
+ <source>No view key supplied, cancelled</source>
+ <translation>Ingen visningsnyckel angiven, avbruten</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="432"/>
+ <source>failed to parse secret view key</source>
+ <translation>det gick inte att parsa hemlig visningsnyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="442"/>
+ <source>failed to verify secret spend key</source>
+ <translation>det gick inte att verifiera hemlig spendernyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="447"/>
+ <source>spend key does not match address</source>
+ <translation>spendernyckel matchar inte adress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="453"/>
+ <source>failed to verify secret view key</source>
+ <translation>det gick inte att verifiera hemlig visningsnyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="458"/>
+ <source>view key does not match address</source>
+ <translation>visningsnyckel matchar inte adress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="477"/>
+ <source>failed to generate new wallet: </source>
+ <translation>det gick inte att skapa ny plånbok: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="799"/>
+ <source>Failed to load unsigned transactions</source>
+ <translation>Det gick inte att läsa in osignerade transaktioner</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="820"/>
+ <source>Failed to load transaction from file</source>
+ <translation>Det gick inte att läsa in transaktion från fil</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="838"/>
+ <source>Wallet is view only</source>
+ <translation>Plånboken är endast för granskning</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="847"/>
+ <source>failed to save file </source>
+ <translation>det gick inte att spara fil </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="874"/>
+ <source>Failed to import key images: </source>
+ <translation>det gick inte att importera nyckelavbildningar: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="987"/>
+ <source>failed to get random outputs to mix: %s</source>
+ <translation>det gick inte att hitta slumpmässiga utgångar att mixa: %s</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1003"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1097"/>
+ <source>not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)</source>
+ <translation>ej tillräckligt med pengar för överföring, endast tillgängligt %s, transaktionsbelopp %s = %s + %s (avgift)</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1012"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1106"/>
+ <source>not enough outputs for specified mixin_count</source>
+ <translation>inte tillräckligt många utgångar för angiven mixin_count</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1014"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1108"/>
+ <source>output amount</source>
+ <translation>utgångens belopp</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1014"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1108"/>
+ <source>found outputs to mix</source>
+ <translation>hittade utgångar att mixa</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1019"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1113"/>
+ <source>transaction was not constructed</source>
+ <translation>transaktionen konstruerades inte</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1023"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1117"/>
+ <source>transaction %s was rejected by daemon with status: </source>
+ <translation>transaktionen %s avvisades av daemonen med status: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1030"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1124"/>
+ <source>one of destinations is zero</source>
+ <translation>ett av målen är noll</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1033"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1127"/>
+ <source>failed to find a suitable way to split transactions</source>
+ <translation>det gick inte att hitta ett lämpligt sätt att dela upp transaktioner</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1036"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1130"/>
+ <source>unknown transfer error: </source>
+ <translation>okänt överföringsfel: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1039"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1133"/>
+ <source>internal error: </source>
+ <translation>internt fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1042"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1136"/>
+ <source>unexpected error: </source>
+ <translation>oväntat fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1045"/>
+ <location filename="../src/wallet/api/wallet.cpp" line="1139"/>
+ <source>unknown error</source>
+ <translation>okänt fel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="1419"/>
+ <source>Rescan spent can only be used with a trusted daemon</source>
+ <translation>Genomsök efter spenderade kan endast användas med en betrodd daemon</translation>
+ </message>
+</context>
+<context>
+ <name>Monero::WalletManagerImpl</name>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="192"/>
+ <source>failed to parse txid</source>
+ <translation>det gick inte att parsa transaktions-id</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="199"/>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="206"/>
+ <source>failed to parse tx key</source>
+ <translation>det gick inte att parsa transaktionsnyckeln</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="217"/>
+ <source>failed to parse address</source>
+ <translation>det gick inte att parsa adressen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="227"/>
+ <source>failed to get transaction from daemon</source>
+ <translation>det gick inte att hämta transaktion från daemon</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="238"/>
+ <source>failed to parse transaction from daemon</source>
+ <translation>det gick inte att parsa transaktion från daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="245"/>
+ <source>failed to validate transaction from daemon</source>
+ <translation>det gick inte att validera transaktion från daemon</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="250"/>
+ <source>failed to get the right transaction from daemon</source>
+ <translation>det gick inte att hämta rätt transaktion från daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="257"/>
+ <source>failed to generate key derivation from supplied parameters</source>
+ <translation>det gick inte att skapa nyckelhärledning från angivna parametrar</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="313"/>
+ <source>error: </source>
+ <translation>fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="319"/>
+ <source>received</source>
+ <translation>mottaget</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="319"/>
+ <source>in txid</source>
+ <translation>i transaktions-id</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet_manager.cpp" line="323"/>
+ <source>received nothing in txid</source>
+ <translation>tog emot ingenting i transaktions-id</translation>
+ </message>
+</context>
+<context>
+ <name>Wallet</name>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="212"/>
+ <source>Failed to parse address</source>
+ <translation>Det gick inte att parsa adressen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="219"/>
+ <source>Failed to parse key</source>
+ <translation>Det gick inte att parsa nyckeln</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="227"/>
+ <source>failed to verify key</source>
+ <translation>det gick inte att verifiera nyckeln</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/api/wallet.cpp" line="237"/>
+ <source>key does not match address</source>
+ <translation>nyckeln matchar inte adressen</translation>
+ </message>
+</context>
+<context>
+ <name>command_line</name>
+ <message>
+ <location filename="../src/common/command_line.cpp" line="76"/>
+ <source>yes</source>
+ <translation>ja</translation>
+ </message>
+</context>
+<context>
+ <name>cryptonote::rpc_args</name>
+ <message>
+ <location filename="../src/rpc/rpc_args.cpp" line="38"/>
+ <source>Specify ip to bind rpc server</source>
+ <translation>Ange IP-adress för att binda till RPC-server</translation>
+ </message>
+ <message>
+ <location filename="../src/rpc/rpc_args.cpp" line="39"/>
+ <source>Specify username[:password] required for RPC server</source>
+ <translation>Ange användarnamn[:lösenord] som krävs av RPC-servern</translation>
+ </message>
+ <message>
+ <location filename="../src/rpc/rpc_args.cpp" line="40"/>
+ <source>Confirm rpc-bind-ip value is NOT a loopback (local) IP</source>
+ <translation>Bekräftelsevärde för rpc-bind-ip är INTE ett lokalt (loopback) IP</translation>
+ </message>
+ <message>
+ <location filename="../src/rpc/rpc_args.cpp" line="66"/>
+ <source>Invalid IP address given for --</source>
+ <translation>Ogiltig IP-adress angiven för --</translation>
+ </message>
+ <message>
+ <location filename="../src/rpc/rpc_args.cpp" line="74"/>
+ <source> permits inbound unencrypted external connections. Consider SSH tunnel or SSL proxy instead. Override with --</source>
+ <translation> tillåter inkommande okrypterade externa anslutningar. Överväg att använda SSH-tunnel eller SSL-proxy istället. Åsidosätt med --</translation>
+ </message>
+ <message>
+ <location filename="../src/rpc/rpc_args.cpp" line="89"/>
+ <source>Username specified with --</source>
+ <translation>Användarnamn angivet med --</translation>
+ </message>
+ <message>
+ <location filename="../src/rpc/rpc_args.cpp" line="89"/>
+ <source> cannot be empty</source>
+ <translation> kan inte vara tomt</translation>
+ </message>
+</context>
+<context>
+ <name>cryptonote::simple_wallet</name>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="290"/>
+ <source>Commands: </source>
+ <translation>Kommandon: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1557"/>
+ <source>failed to read wallet password</source>
+ <translation>det gick inte att läsa lösenord för plånboken</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1325"/>
+ <source>invalid password</source>
+ <translation>ogiltigt lösenord</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="697"/>
+ <source>start_mining [&lt;number_of_threads>] - Start mining in daemon</source>
+ <translation>start_mining [&lt;antal_trådar>] - Starta brytning i daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="698"/>
+ <source>Stop mining in daemon</source>
+ <translation>Avbryt brytning i daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="699"/>
+ <source>Save current blockchain data</source>
+ <translation>Spara aktuella blockkedje-data</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="701"/>
+ <source>Show current wallet balance</source>
+ <translation>Visa aktuellt saldo för plånboken</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="704"/>
+ <source>Show blockchain height</source>
+ <translation>Visa blockkedjans höjd</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="715"/>
+ <source>Show current wallet public address</source>
+ <translation>Visa plånbokens aktuella öppna adress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="744"/>
+ <source>Show this help</source>
+ <translation>Visa denna hjälp</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="788"/>
+ <source>set seed: needs an argument. available options: language</source>
+ <translation>set seed: behöver ett argument. tillgängliga alternativ: språk</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="811"/>
+ <source>set: unrecognized argument(s)</source>
+ <translation>set: okända argument</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1442"/>
+ <source>wallet file path not valid: </source>
+ <translation>ogiltig sökväg till plånbok: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="863"/>
+ <source>Attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting.</source>
+ <translation>Försöker skapa eller återställa plånbok, men angivna filer existerar. Avslutar för att inte riskera att skriva över någonting.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="416"/>
+ <source>usage: payment_id</source>
+ <translation>användning: payment_id</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="710"/>
+ <source>sweep_below &lt;amount_threshold> [mixin] address [payment_id] - Send all unlocked outputs below the threshold to an address</source>
+ <translation>sweep_below &lt;tröskelbelopp> [mixin] &lt;adress> [&lt;betalnings_ID>] - Skicka alla upplåsta utgångar under tröskelbeloppet till en adress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="743"/>
+ <source>Generate a new random full size payment id - these will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids</source>
+ <translation>Skapa ett nytt slumpmässigt betalnings-ID av full storlek - dessa kommer att vara okrypterade på blockkedjan, se integrated_address för krypterade korta betalnings-ID</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="774"/>
+ <source>needs an argument</source>
+ <translation>kräver ett argument</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="797"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="798"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="799"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="801"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="804"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="805"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="809"/>
+ <source>0 or 1</source>
+ <translation>0 eller 1</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="800"/>
+ <source>integer >= 2</source>
+ <translation>heltal >= 2</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="803"/>
+ <source>0, 1, 2, 3, or 4</source>
+ <translation>0, 1, 2, 3 eller 4</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="807"/>
+ <source>unsigned integer</source>
+ <translation>positivt heltal</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="912"/>
+ <source>NOTE: the following 25 words can be used to recover access to your wallet. Write them down and store them somewhere safe and secure. Please do not store them in your email or on file storage services outside of your immediate control.
+</source>
+ <translation>OBSERVERA: följande 25 ord kan användas för att återfå tillgång till din plånbok. Skriv ner och spara dem på ett säkert ställe. Spara dem inte i din e-post eller på något lagringsutrymme som du inte har direkt kontroll över.
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="958"/>
+ <source>--restore-deterministic-wallet uses --generate-new-wallet, not --wallet-file</source>
+ <translation>--restore-deterministic-wallet använder --generate-new-wallet, inte --wallet-file</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="973"/>
+ <source>specify a recovery parameter with the --electrum-seed=&quot;words list here&quot;</source>
+ <translation>ange en återställningsparameter med --electrum-seed=&quot;ordlista här&quot;</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1123"/>
+ <source>specify a wallet path with --generate-new-wallet (not --wallet-file)</source>
+ <translation>ange sökväg till en plånbok med --generate-new-wallet (inte --wallet-file)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1261"/>
+ <source>wallet failed to connect to daemon: </source>
+ <translation>plånboken kunde inte ansluta till daemonen: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1269"/>
+ <source>Daemon uses a different RPC major version (%u) than the wallet (%u): %s. Either update one of them, or use --allow-mismatched-daemon-version.</source>
+ <translation>Daemonen använder en högre version av RPC (%u) än plånboken (%u): %s. Antingen uppdatera en av dem, eller använd --allow-mismatched-daemon-version.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1288"/>
+ <source>List of available languages for your wallet&apos;s seed:</source>
+ <translation>Lista över tillgängliga språk för din plånboks frö:</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1297"/>
+ <source>Enter the number corresponding to the language of your choice: </source>
+ <translation>Ange det tal som motsvarar det språk du vill använda: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1354"/>
+ <source>You had been using a deprecated version of the wallet. Please use the new seed that we provide.
+</source>
+ <translation>Du hade använt en inaktuell version av plånboken. Använd det nya frö som vi tillhandahåller.
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1368"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1425"/>
+ <source>Generated new wallet: </source>
+ <translation>Ny plånbok skapad: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1374"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1430"/>
+ <source>failed to generate new wallet: </source>
+ <translation>det gick inte att skapa ny plånbok: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1457"/>
+ <source>Opened watch-only wallet</source>
+ <translation>Öppnade plånbok för granskning</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1457"/>
+ <source>Opened wallet</source>
+ <translation>Öppnade plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1466"/>
+ <source>You had been using a deprecated version of the wallet. Please proceed to upgrade your wallet.
+</source>
+ <translation>Du hade använt en inaktuell version av plånboken. Fortsätt för att uppgradera din plånbok.
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1481"/>
+ <source>You had been using a deprecated version of the wallet. Your wallet file format is being upgraded now.
+</source>
+ <translation>Du hade använt en inaktuell version av plånboken. Plånbokens filformat kommer nu att uppgraderas.
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1489"/>
+ <source>failed to load wallet: </source>
+ <translation>det gick inte att läsa in plånboken: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1497"/>
+ <source>Use the &quot;help&quot; command to see the list of available commands.
+</source>
+ <translation>Använd kommandot &quot;help&quot; för att se en lista över tillgängliga kommandon.
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1541"/>
+ <source>Wallet data saved</source>
+ <translation>Plånboksdata sparades</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1613"/>
+ <source>Mining started in daemon</source>
+ <translation>Brytning startad i daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1615"/>
+ <source>mining has NOT been started: </source>
+ <translation>brytning har INTE startats: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1634"/>
+ <source>Mining stopped in daemon</source>
+ <translation>Brytning stoppad i daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1636"/>
+ <source>mining has NOT been stopped: </source>
+ <translation>brytning har INTE stoppats: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1655"/>
+ <source>Blockchain saved</source>
+ <translation>Blockkedjan sparad</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1670"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1687"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1699"/>
+ <source>Height </source>
+ <translation>Höjd </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1671"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1688"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1700"/>
+ <source>transaction </source>
+ <translation>transaktion </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1672"/>
+ <source>received </source>
+ <translation>mottaget </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1689"/>
+ <source>spent </source>
+ <translation>spenderad </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1701"/>
+ <source>unsupported transaction format</source>
+ <translation>transaktionsformatet stöds inte</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1718"/>
+ <source>Starting refresh...</source>
+ <translation>Startar uppdatering …</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1731"/>
+ <source>Refresh done, blocks received: </source>
+ <translation>Uppdatering färdig, mottagna block: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2186"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2701"/>
+ <source>payment id has invalid format, expected 16 or 64 character hex string: </source>
+ <translation>betalnings-ID har ogiltigt format. En 16- eller 64-teckens hex-sträng förväntades: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2201"/>
+ <source>bad locked_blocks parameter:</source>
+ <translation>dålig parameter för locked_blocks:</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2228"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2726"/>
+ <source>a single transaction cannot use more than one payment id: </source>
+ <translation>en enstaka transaktion kan inte använda mer än ett betalnings-ID: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2237"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2735"/>
+ <source>failed to set up payment id, though it was decoded correctly</source>
+ <translation>det gick inte att upprätta betalnings-ID, trots att det avkodades korrekt</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2262"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2355"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2533"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2749"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2794"/>
+ <source>transaction cancelled.</source>
+ <translation>transaktion avbröts.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2323"/>
+ <source>Sending %s. </source>
+ <translation>Skickar %s. </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2326"/>
+ <source>Your transaction needs to be split into %llu transactions. This will result in a transaction fee being applied to each transaction, for a total fee of %s</source>
+ <translation>Transaktionen behöver delas upp i %llu transaktioner. Detta kommer att göra att en transaktionsavgift läggs till varje transaktion, med ett totalt belopp på %s</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2332"/>
+ <source>The transaction fee is %s</source>
+ <translation>Transaktionsavgiften är %s</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2335"/>
+ <source>, of which %s is dust from change</source>
+ <translation>, varav %s är damm från växel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2336"/>
+ <source>.</source>
+ <translation>.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2336"/>
+ <source>A total of %s from dust change will be sent to dust address</source>
+ <translation>Ett total belopp på %s från växeldamm kommer att skickas till damm-adressen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2341"/>
+ <source>.
+This transaction will unlock on block %llu, in approximately %s days (assuming 2 minutes per block)</source>
+ <translation>.
+Denna transaktion kommer att låsas upp vid block %llu, om ungefär %s dagar (förutsatt en blocktid på 2 minuter)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2367"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2544"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2805"/>
+ <source>Failed to write transaction(s) to file</source>
+ <translation>Det gick inte att skriva transaktioner till fil</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2371"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2548"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2809"/>
+ <source>Unsigned transaction(s) successfully written to file: </source>
+ <translation>Osignerade transaktioner skrevs till fil: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2406"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2583"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2844"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3157"/>
+ <source>Not enough money in unlocked balance</source>
+ <translation>Inte tillräckligt med pengar i upplåst saldo</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2415"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2592"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2853"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3166"/>
+ <source>Failed to find a way to create transactions. This is usually due to dust which is so small it cannot pay for itself in fees, or trying to send more money than the unlocked balance, or not leaving enough for fees</source>
+ <translation>Det gick inte att hitta något sätt att skapa transaktioner. Detta beror vanligtvis på damm som är så litet att det inte kan betala för sig självt i avgifter, eller ett försök att skicka mer pengar än upplåst saldo, eller att inte lämna tillräckligt för att täcka avgifterna</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2435"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2612"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2873"/>
+ <source>Reason: </source>
+ <translation>Orsak: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2447"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2624"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2885"/>
+ <source>failed to find a suitable way to split transactions</source>
+ <translation>det gick inte att hitta ett lämpligt sätt att dela upp transaktioner</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2503"/>
+ <source>No unmixable outputs found</source>
+ <translation>Inga omixbara utgångar kunde hittas</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2709"/>
+ <source>No address given</source>
+ <translation>Ingen adress har angivits</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2921"/>
+ <source>missing amount threshold</source>
+ <translation>beloppströskel saknas</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2926"/>
+ <source>invalid amount threshold</source>
+ <translation>ogiltig beloppströskel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3008"/>
+ <source>Claimed change does not go to a paid address</source>
+ <translation>Begärd växel går inte till en betald adress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3013"/>
+ <source>Claimed change is larger than payment to the change address</source>
+ <translation>Begärd växel är större än betalning till växeladressen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3035"/>
+ <source>sending %s to %s</source>
+ <translation>skickar %s till %s</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3041"/>
+ <source>with no destinations</source>
+ <translation>utan några mål</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3088"/>
+ <source>Failed to sign transaction</source>
+ <translation>Det gick inte att signera transaktionen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3094"/>
+ <source>Failed to sign transaction: </source>
+ <translation>Det gick inte att signera transaktion: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3120"/>
+ <source>Failed to load transaction from file</source>
+ <translation>Det gick inte att läsa in transaktion från fil</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3137"/>
+ <source>daemon is busy. Please try later</source>
+ <translation>daemonen är upptagen. Försök senare</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1745"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1995"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2395"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2572"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2833"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3146"/>
+ <source>RPC error: </source>
+ <translation>RPC-fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="312"/>
+ <source>wallet is watch-only and has no spend key</source>
+ <translation>plånboken är enbart för granskning och har ingen spendernyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="390"/>
+ <source>Your original password was incorrect.</source>
+ <translation>Ditt ursprungliga lösenord var fel.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="404"/>
+ <source>Error with wallet rewrite: </source>
+ <translation>Fel vid återskrivning av plånbok: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="513"/>
+ <source>priority must be 0, 1, 2, 3, or 4 </source>
+ <translation>prioritet måste vara 0, 1, 2, 3 eller 4 </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="525"/>
+ <source>priority must be 0, 1, 2, 3,or 4</source>
+ <translation>prioritet måste vara 0, 1, 2, 3 eller 4</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="540"/>
+ <source>priority must be 0, 1, 2 3,or 4</source>
+ <translation>prioritet måste vara 0, 1, 2, 3 eller 4</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="623"/>
+ <source>invalid unit</source>
+ <translation>ogiltig enhet</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="641"/>
+ <source>invalid count: must be an unsigned integer</source>
+ <translation>ogiltigt värde för count: måste vara ett heltal utan tecken</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="659"/>
+ <source>invalid value</source>
+ <translation>ogiltigt värde</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="705"/>
+ <source>Same as transfer, but using an older transaction building algorithm</source>
+ <translation>Samma som transfer, men använder en äldre algoritm för att bygga transaktionen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="709"/>
+ <source>sweep_all [mixin] address [payment_id] - Send all unlocked balance to an address</source>
+ <translation>sweep_all [mixin] adress [betalnings_id] - Skicka allt upplåst saldo till en adress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="711"/>
+ <source>donate [&lt;mixin_count>] &lt;amount> [payment_id] - Donate &lt;amount> to the development team (donate.getmonero.org)</source>
+ <translation>donate [&lt;mixin_antal>] &lt;belopp> [&lt;betalnings_id>] - Donera &lt;belopp> till utvecklingsteamet (donate.getmonero.org)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="714"/>
+ <source>set_log &lt;level>|&lt;categories> - Change current log detail (level must be &lt;0-4>)</source>
+ <translation>set_log &lt;nivå>|&lt;kategorier> - Ändra detaljnivån för aktuell logg (nivå måste vara 0-4)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="717"/>
+ <source>address_book [(add (&lt;address> [pid &lt;long or short payment id>])|&lt;integrated address> [&lt;description possibly with whitespaces>])|(delete &lt;index>)] - Print all entries in the address book, optionally adding/deleting an entry to/from it</source>
+ <translation>address_book [(add (&lt;adress> [pid &lt;långt eller kort betalnings-ID>])|&lt;integrerad adress> [&lt;beskrivning eventuellt med blanktecken>])|(delete &lt;index>)] - Skriv ut alla poster i adressboken, eventuellt lägg till/ta bort en post till/från den</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="729"/>
+ <source>show_transfers [in|out|pending|failed|pool] [&lt;min_height> [&lt;max_height>]] - Show incoming/outgoing transfers within an optional height range</source>
+ <translation>show_transfers [in|out|pending|failed|pool] [&lt;min_höjd> [&lt;max_höjd>]] - Visa inkommande/utgående överföringar inom ett valfritt höjdintervall</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="741"/>
+ <source>Show information about a transfer to/from this address</source>
+ <translation>Visa information om en överföring till/från denna adress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="742"/>
+ <source>Change wallet password</source>
+ <translation>Ändra lösenord för plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="820"/>
+ <source>usage: set_log &lt;log_level_number_0-4> | &lt;categories></source>
+ <translation>användning: set_log &lt;loggnivå_nummer_0-4> | &lt;kategorier></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="886"/>
+ <source>(Y/Yes/N/No): </source>
+ <translation>(J/Ja/N/Nej): </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1157"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1184"/>
+ <source>bad m_restore_height parameter: </source>
+ <translation>dålig parameter för m_restore_height: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1162"/>
+ <source>date format must be YYYY-MM-DD</source>
+ <translation>datumformat måste vara ÅÅÅÅ-MM-DD</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1175"/>
+ <source>Restore height is: </source>
+ <translation>Återställningshöjd är: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1176"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2348"/>
+ <source>Is this okay? (Y/Yes/N/No): </source>
+ <translation>Är detta okej? (J/Ja/N/Nej): </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1212"/>
+ <source>Daemon is local, assuming trusted</source>
+ <translation>Daemonen är lokal, utgår från att den är betrodd</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1553"/>
+ <source>Password for new watch-only wallet</source>
+ <translation>Lösenord för ny granskningsplånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1604"/>
+ <source>invalid arguments. Please use start_mining [&lt;number_of_threads>] [do_bg_mining] [ignore_battery], &lt;number_of_threads> should be from 1 to </source>
+ <translation>ogiltiga argument. Använd start_mining [&lt;antal_trådar>] [do_bg_mining] [ignore_battery], &lt;antal_trådar> ska vara från 1 till </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1755"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2457"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2634"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2895"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3205"/>
+ <source>internal error: </source>
+ <translation>internt fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1760"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2000"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2462"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2639"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2900"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3210"/>
+ <source>unexpected error: </source>
+ <translation>oväntat fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1765"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2005"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2467"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2644"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2905"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3215"/>
+ <source>unknown error</source>
+ <translation>okänt fel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1770"/>
+ <source>refresh failed: </source>
+ <translation>det gick inte att att uppdatera: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1770"/>
+ <source>Blocks received: </source>
+ <translation>Mottagna block: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1795"/>
+ <source>unlocked balance: </source>
+ <translation>upplåst saldo: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="808"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1846"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1896"/>
+ <source>amount</source>
+ <translation>belopp</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1846"/>
+ <source>spent</source>
+ <translation>spenderad</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1846"/>
+ <source>global index</source>
+ <translation>globalt index</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1846"/>
+ <source>tx id</source>
+ <translation>tx-ID</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1868"/>
+ <source>No incoming transfers</source>
+ <translation>Inga inkommande överföringar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1872"/>
+ <source>No incoming available transfers</source>
+ <translation>Inga inkommande tillgängliga överföringar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1876"/>
+ <source>No incoming unavailable transfers</source>
+ <translation>Inga inkommande otillgängliga överföringar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1887"/>
+ <source>expected at least one payment_id</source>
+ <translation>åtminstone ett payment_id förväntades</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1896"/>
+ <source>payment</source>
+ <translation>betalning</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1896"/>
+ <source>transaction</source>
+ <translation>transaktion</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1896"/>
+ <source>height</source>
+ <translation>höjd</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1896"/>
+ <source>unlock time</source>
+ <translation>upplåsningstid</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1908"/>
+ <source>No payments with id </source>
+ <translation>Inga betalningar med ID </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1960"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2026"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2280"/>
+ <source>failed to get blockchain height: </source>
+ <translation>det gick inte att hämta blockkedjans höjd: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2016"/>
+ <source>failed to connect to the daemon</source>
+ <translation>det gick inte att ansluta till daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2034"/>
+ <source>
+Transaction %llu/%llu: txid=%s</source>
+ <translation>
+Transaktion %llu/%llu: txid=%s</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2044"/>
+ <source>
+Input %llu/%llu: amount=%s</source>
+ <translation>
+Ingång %llu/%llu: belopp=%s</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2060"/>
+ <source>failed to get output: </source>
+ <translation>det gick inte att hämta utgång: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2068"/>
+ <source>output key&apos;s originating block height shouldn&apos;t be higher than the blockchain height</source>
+ <translation>utgångsnyckelns ursprungsblockhöjd får inte vara högre än blockkedjans höjd</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2072"/>
+ <source>
+Originating block heights: </source>
+ <translation>
+Ursprungsblockhöjder: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2087"/>
+ <source>
+|</source>
+ <translation>
+|</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2087"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3915"/>
+ <source>|
+</source>
+ <translation>|
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2104"/>
+ <source>
+Warning: Some input keys being spent are from </source>
+ <translation>
+Varning: Några ingångsnycklar som spenderas kommer från </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2106"/>
+ <source>, which can break the anonymity of ring signature. Make sure this is intentional!</source>
+ <translation>, vilket kan bryta ringsignaturens anonymitet. Se till att detta är avsiktligt!</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2152"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2937"/>
+ <source>wrong number of arguments</source>
+ <translation>fel antal argument</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2257"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2744"/>
+ <source>No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): </source>
+ <translation>Inget betalnings-ID har inkluderats med denna transaktion. Är detta okej? (J/Ja/N/Nej): </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2298"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2762"/>
+ <source>No outputs found, or daemon is not ready</source>
+ <translation>Inga utgångar hittades, eller så är daemonen inte redo</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2399"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2576"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2837"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3150"/>
+ <source>failed to get random outputs to mix: </source>
+ <translation>det gick inte att hitta slumpmässiga utgångar att mixa: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2518"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2779"/>
+ <source>Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): </source>
+ <translation>Sveper upp %s i %llu transaktioner för en total avgift på %s. Är detta okej? (J/Ja/N/Nej): </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2524"/>
+ <source>Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): </source>
+ <translation>Sveper upp %s för en total avgift på %s. Är detta okej? (J/Ja/N/Nej): </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2969"/>
+ <source>Donating </source>
+ <translation>Donerar </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3053"/>
+ <source>Loaded %lu transactions, for %s, fee %s, %s, %s, with min mixin %lu. %sIs this okay? (Y/Yes/N/No): </source>
+ <translation>Läste in %lu transaktioner, för %s, avgift %s, %s, %s, med minsta mixin %lu. %sÄr detta okej? (J/Ja/N/Nej): </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3077"/>
+ <source>This is a watch only wallet</source>
+ <translation>Detta är en granskningsplånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4443"/>
+ <source>usage: show_transfer &lt;txid></source>
+ <translation>användning: show_transfer &lt;transaktions-ID></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4557"/>
+ <source>Transaction ID not found</source>
+ <translation>Transaktions-ID kunde inte hittas</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="237"/>
+ <source>true</source>
+ <translation>sant</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="266"/>
+ <source>failed to parse refresh type</source>
+ <translation>det gick inte att parsa uppdateringstyp</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="330"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="362"/>
+ <source>wallet is watch-only and has no seed</source>
+ <translation>plånboken är enbart för granskning och saknar frö</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="353"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="367"/>
+ <source>wallet is non-deterministic and has no seed</source>
+ <translation>plånboken är icke-deterministisk och saknar frö</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="450"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="467"/>
+ <source>wallet is watch-only and cannot transfer</source>
+ <translation>plånboken är enbart för granskning och kan inte göra överföringar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="474"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="480"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="496"/>
+ <source>mixin must be an integer >= 2</source>
+ <translation>mixin måste vara ett heltal >= 2</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="501"/>
+ <source>could not change default mixin</source>
+ <translation>det gick inte att ändra standardinställning för mixin</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="545"/>
+ <source>could not change default priority</source>
+ <translation>Det gick inte att ändra standardinställning för prioritet</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="700"/>
+ <source>Synchronize transactions and balance</source>
+ <translation>Synkronisera transaktioner och saldo</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="702"/>
+ <source>incoming_transfers [available|unavailable] - Show incoming transfers, all or filtered by availability</source>
+ <translation>incoming_transfers [available|unavailable] - Visa inkommande överföringar, alla eller filtrerade efter tillgänglighet</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="703"/>
+ <source>payments &lt;PID_1> [&lt;PID_2> ... &lt;PID_N>] - Show payments for given payment ID[s]</source>
+ <translation>payments &lt;B_ID_1> [&lt;B_ID_2> … &lt;B_ID_N>] - Visa betalningar för angivna betalnings-ID</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="706"/>
+ <source>transfer [&lt;priority>] [&lt;mixin_count>] &lt;address> &lt;amount> [&lt;payment_id>] - Transfer &lt;amount> to &lt;address>. &lt;priority> is the priority of the transaction. The higher the priority, the higher the fee of the transaction. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command &quot;set priority&quot;) is used. &lt;mixin_count> is the number of extra inputs to include for untraceability. Multiple payments can be made at once by adding &lt;address_2> &lt;amount_2> etcetera (before the payment ID, if it&apos;s included)</source>
+ <translation>transfer [&lt;prioritet>] [&lt;mixin_antal>] &lt;adress> &lt;belopp> [&lt;betalnings_id>] - Överför &lt;belopp> till &lt;adress>. &lt;prioritet> är transaktionens prioritet. Ju högre prioritet, desto högre transaktionsavgift. Giltiga värden i prioritetsordning (från lägsta till högsta) är: unimportant, normal, elevated, priority. Om det utelämnas kommer standardvärdet (se kommandot &quot;set priority&quot;) att användas. &lt;mixin_antal> är det antal extra ingångar som ska inkluderas för att uppnå ospårbarhet. Flera betalningar kan göras på en gång genom att lägga till &lt;adress_2> &lt;belopp_2> etcetera (före betalnings-ID, om det inkluderas)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="707"/>
+ <source>locked_transfer [&lt;mixin_count>] &lt;addr> &lt;amount> &lt;lockblocks>(Number of blocks to lock the transaction for, max 1000000) [&lt;payment_id>]</source>
+ <translation>locked_transfer [&lt;mixin_antal>] &lt;adress> &lt;belopp> &lt;låsblock>(Antal block som transaktionen ska låsas för, max 1000000) [&lt;betalnings_id>]</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="708"/>
+ <source>Send all unmixable outputs to yourself with mixin 0</source>
+ <translation>Skicka alla omixbara utgångar till dig själv med mixin 0</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="712"/>
+ <source>Sign a transaction from a file</source>
+ <translation>Signera en transaktion från en fil</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="713"/>
+ <source>Submit a signed transaction from a file</source>
+ <translation>Skicka en signerad transaktion från en fil</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="716"/>
+ <source>integrated_address [PID] - Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID</source>
+ <translation>integrated_address [PID] - Koda ett betalnings-ID till en integrerad adress för den aktuella plånbokens öppna adress (utan argument används ett slumpmässigt betalnings-ID), eller avkoda en integrerad adress till standardadress och betalnings-ID</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="718"/>
+ <source>Save wallet data</source>
+ <translation>Spara plånboksdata</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="719"/>
+ <source>Save a watch-only keys file</source>
+ <translation>Spara en fil med granskningsnycklar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="720"/>
+ <source>Display private view key</source>
+ <translation>Visa privat visningsnyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="721"/>
+ <source>Display private spend key</source>
+ <translation>Visa privat spendernyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="722"/>
+ <source>Display Electrum-style mnemonic seed</source>
+ <translation>Visa minnesfrö (Electrum-typ)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="723"/>
+ <source>Available options: seed language - set wallet seed language; always-confirm-transfers &lt;1|0> - whether to confirm unsplit txes; print-ring-members &lt;1|0> - whether to print detailed information about ring members during confirmation; store-tx-info &lt;1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin &lt;n> - set default mixin (default is 4); auto-refresh &lt;1|0> - whether to automatically sync new blocks from the daemon; refresh-type &lt;full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [0|1|2|3|4] - default/unimportant/normal/elevated/priority fee; confirm-missing-payment-id &lt;1|0>; ask-password &lt;1|0>; unit &lt;monero|millinero|micronero|nanonero|piconero> - set default monero (sub-)unit; min-outputs-count [n] - try to keep at least that many outputs of value at least min-outputs-value; min-outputs-value [n] - try to keep at least min-outputs-count outputs of at least that value; merge-destinations &lt;1|0> - whether to merge multiple payments to the same destination address</source>
+ <translation>Tillgängliga alternativ: seed language - ange språk för plånbokens frö; always-confirm-transfers &lt;1|0> - huruvida ej delade transaktioner ska bekräftas; print-ring-members &lt;1|0> - huruvida detaljerad information om ringmedlemmar ska skrivas ut vid bekräftelse; store-tx-info &lt;1|0> - huruvida info om utgående transaktioner ska sparas (måladress, betalnings-ID, hemlig transaktionsnyckel) för framtida referens; default-mixin &lt;n> - ange standardvärde för mixin (standard är 4); auto-refresh &lt;1|0> - huruvida nya block från daemonen ska synkas automatiskt; refresh-type &lt;full|optimize-coinbase|no-coinbase|default> - ange uppdateringsbeteende för plånbok; priority [0|1|2|3|4] - standard/oviktigt/normal/förhöjd/prioritetsavgift; confirm-missing-payment-id &lt;1|0>; ask-password &lt;1|0>; unit &lt;monero|millinero|micronero|nanonero|piconero> - ange standardvärde för monero-(under-)enhet; min-outputs-count [n] - försök behålla åtminstone så många utgångar med ett värde på åtminstone min-outputs-value; min-outputs-value [n] - försök behålla åtminstone min-outputs-count utgångar av åtminstone detta värde; merge-destinations &lt;1|0> - huruvida flera betalningar till samma måladress ska slås samman</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="724"/>
+ <source>Rescan blockchain for spent outputs</source>
+ <translation>Genomsök blockkedjan igen för spenderade utgångar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="725"/>
+ <source>Get transaction key (r) for a given &lt;txid></source>
+ <translation>Hämta transaktionsnyckel (r) för ett givet &lt;transaktions-ID></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="726"/>
+ <source>Check amount going to &lt;address> in &lt;txid></source>
+ <translation>Kontrollera belopp som går till &lt;adress> i &lt;transaktions-ID></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="727"/>
+ <source>Generate a signature to prove payment to &lt;address> in &lt;txid> using the transaction secret key (r) without revealing it</source>
+ <translation>Skapa en signatur för att bevisa betalning till &lt;adress> i &lt;transaktions-ID> genom att använda hemlig nyckel för transaktion (r) utan att avslöja den</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="728"/>
+ <source>Check tx proof for payment going to &lt;address> in &lt;txid></source>
+ <translation>Kontrollera transaktionsbevis för betalning som går till &lt;adress> i &lt;transaktions-ID></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="730"/>
+ <source>unspent_outputs [&lt;min_amount> &lt;max_amount>] - Show unspent outputs within an optional amount range</source>
+ <translation>unspent_outputs [&lt;min_belopp> &lt;max_belopp>] - Visa ej spenderade utgångar inom ett valfritt beloppsintervall</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="731"/>
+ <source>Rescan blockchain from scratch</source>
+ <translation>Genomsök blockkedjan från början</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="732"/>
+ <source>Set an arbitrary string note for a txid</source>
+ <translation>Ange en godtycklig sträng som anteckning för ett transaktions-ID</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="733"/>
+ <source>Get a string note for a txid</source>
+ <translation>Hämta en stränganteckning för ett transaktions-ID</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="734"/>
+ <source>Show wallet status information</source>
+ <translation>Visa statusinformation för plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="735"/>
+ <source>Sign the contents of a file</source>
+ <translation>Signera innehållet i en fil</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="736"/>
+ <source>Verify a signature on the contents of a file</source>
+ <translation>Verifera signaturen för innehållet i en fil</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="737"/>
+ <source>Export a signed set of key images</source>
+ <translation>Exportera en signerad uppsättning nyckelavbildningar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="738"/>
+ <source>Import signed key images list and verify their spent status</source>
+ <translation>Importera lista med signerade nyckelavbildningar och verifera deras spenderingsstatus</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="739"/>
+ <source>Export a set of outputs owned by this wallet</source>
+ <translation>Exportera en uppsättning utgångar som ägs av denna plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="740"/>
+ <source>Import set of outputs owned by this wallet</source>
+ <translation>Importera en uppsättning utgångar som ägs av denna plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="802"/>
+ <source>full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)</source>
+ <translation>full (långsammast, inga antaganden); optimize-coinbase (snabb, antar att hela coinbase-transaktionen betalas till en enda adress); no-coinbase (snabbast, antar att ingen coinbase-transaktion tas emot), default (samma som optimize-coinbase)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="806"/>
+ <source>monero, millinero, micronero, nanonero, piconero</source>
+ <translation>monero, millinero, micronero, nanonero, piconero</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="851"/>
+ <source>Wallet name not valid. Please try again or use Ctrl-C to quit.</source>
+ <translation>Plånbokens namn ej giltigt. Försök igen eller använd Ctrl-C för att avsluta.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="868"/>
+ <source>Wallet and key files found, loading...</source>
+ <translation>Plånbok och nyckelfil hittades, läser in …</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="874"/>
+ <source>Key file found but not wallet file. Regenerating...</source>
+ <translation>Nyckelfil hittades men inte plånboksfilen. Återskapar …</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="880"/>
+ <source>Key file not found. Failed to open wallet: </source>
+ <translation>Nyckelfilen kunde inte hittas. Det gick inte att öppna plånbok: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="894"/>
+ <source>Generating new wallet...</source>
+ <translation>Skapar ny plånbok …</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="937"/>
+ <source>can&apos;t specify more than one of --generate-new-wallet=&quot;wallet_name&quot;, --wallet-file=&quot;wallet_name&quot;, --generate-from-view-key=&quot;wallet_name&quot;, --generate-from-json=&quot;jsonfilename&quot; and --generate-from-keys=&quot;wallet_name&quot;</source>
+ <translation>det går inte att ange mer än en av --generate-new-wallet=&quot;plånboksnamn&quot;, --wallet-file=&quot;plånboksnamn&quot;, --generate-from-view-key=&quot;plånboksnamn&quot;, --generate-from-json=&quot;json-filnamn&quot; och --generate-from-keys=&quot;plånboksnamn&quot;</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="953"/>
+ <source>can&apos;t specify both --restore-deterministic-wallet and --non-deterministic</source>
+ <translation>det går inte att ange både --restore-deterministic-wallet och --non-deterministic</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="982"/>
+ <source>Electrum-style word list failed verification</source>
+ <translation>det gick inte att verifiera ordlista av Electrum-typ</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="994"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1011"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1046"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1063"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1079"/>
+ <source>No data supplied, cancelled</source>
+ <translation>Ingen data angiven, avbryter</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1002"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1054"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2220"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2718"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3276"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3378"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3530"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4048"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4239"/>
+ <source>failed to parse address</source>
+ <translation>det gick inte att parsa adressen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1017"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1085"/>
+ <source>failed to parse view key secret key</source>
+ <translation>det gick inte att parsa hemlig visningsnyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1027"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1103"/>
+ <source>failed to verify view key secret key</source>
+ <translation>det gick inte att verifiera hemlig visningsnyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1031"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1107"/>
+ <source>view key does not match standard address</source>
+ <translation>visningsnyckel matchar inte standardadress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1036"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1111"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1128"/>
+ <source>account creation failed</source>
+ <translation>det gick inte att skapa konto</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1069"/>
+ <source>failed to parse spend key secret key</source>
+ <translation>det gick inte att parsa spendernyckel hemlig nyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1095"/>
+ <source>failed to verify spend key secret key</source>
+ <translation>det gick inte att verifiera spendernyckel hemlig nyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1099"/>
+ <source>spend key does not match standard address</source>
+ <translation>spendernyckel matchar inte standardadress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1199"/>
+ <source>failed to open account</source>
+ <translation>det gick inte att öppna konto</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1203"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1579"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1626"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1647"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3348"/>
+ <source>wallet is null</source>
+ <translation>plånbok är null</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1262"/>
+ <source>Daemon either is not started or wrong port was passed. Please make sure daemon is running or restart the wallet with the correct daemon address.</source>
+ <translation>Antingen har daemonen inte startat eller så angavs fel port. Se till att daemonen kör eller starta om plånboken med korrekt daemonadress.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1306"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1311"/>
+ <source>invalid language choice passed. Please try again.
+</source>
+ <translation>ogiltigt språkval angavs. Försök igen.
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1370"/>
+ <source>View key: </source>
+ <translation>Visningsnyckel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1385"/>
+ <source>Your wallet has been generated!
+To start synchronizing with the daemon, use the &quot;refresh&quot; command.
+Use the &quot;help&quot; command to see the list of available commands.
+Always use the &quot;exit&quot; command when closing monero-wallet-cli to save
+your current session&apos;s state. Otherwise, you might need to synchronize
+your wallet again (your wallet keys are NOT at risk in any case).
+</source>
+ <translation>Din plånbok har skapats!
+För att starta synkronisering med daemonen, använd kommandot &quot;refresh&quot;.
+Använd kommandot &quot;help&quot; för att se en lista över tillgängliga kommandon.
+Använd alltid kommandot &quot;exit&quot; när du stänger monero-wallet-cli så att ditt aktuella sessionstillstånd sparas. Annars kan du bli tvungen att synkronisera
+din plånbok igen (din plånboks nycklar är dock INTE hotade i vilket fall som helst).
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1492"/>
+ <source>You may want to remove the file &quot;%s&quot; and try again</source>
+ <translation>Du kan också vilja ta bort filen &quot;%s&quot; och försöka igen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1518"/>
+ <source>failed to deinitialize wallet</source>
+ <translation>det gick inte att avinitiera plånboken</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1570"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1968"/>
+ <source>this command requires a trusted daemon. Enable with --trusted-daemon</source>
+ <translation>detta kommando kräver en betrodd daemon. Aktivera med --trusted-daemon</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1657"/>
+ <source>blockchain can&apos;t be saved: </source>
+ <translation>blockkedjan kan inte sparas: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1736"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1982"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2386"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2563"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2824"/>
+ <source>daemon is busy. Please try again later.</source>
+ <translation>daemonen är upptagen. Försök igen senare.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1740"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1986"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2390"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2567"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2828"/>
+ <source>no connection to daemon. Please make sure daemon is running.</source>
+ <translation>ingen anslutning till daemonen. Se till att daemonen körs.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1750"/>
+ <source>refresh error: </source>
+ <translation>fel vid uppdatering: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1794"/>
+ <source>Balance: </source>
+ <translation>Saldo: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1845"/>
+ <source>pubkey</source>
+ <translation>öppen nyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1845"/>
+ <source>key image</source>
+ <translation>nyckelavbildning</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1846"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1856"/>
+ <source>unlocked</source>
+ <translation>upplåst</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1846"/>
+ <source>ringct</source>
+ <translation>ringct</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1855"/>
+ <source>T</source>
+ <translation>S</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1855"/>
+ <source>F</source>
+ <translation>F</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1856"/>
+ <source>locked</source>
+ <translation>låst</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1857"/>
+ <source>RingCT</source>
+ <translation>RingCT</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1857"/>
+ <source>-</source>
+ <translation>-</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1929"/>
+ <source>payment ID has invalid format, expected 16 or 64 character hex string: </source>
+ <translation>betalnings-ID har ogiltigt format, en 16- eller 64-teckens hex-sträng förväntades: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="1990"/>
+ <source>failed to get spent status</source>
+ <translation>det gick inte att hämta spenderingsstatus</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2105"/>
+ <source>the same transaction</source>
+ <translation>samma transaktion</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2105"/>
+ <source>blocks that are temporally very close</source>
+ <translation>block som ligger väldigt nära varandra i tiden</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2206"/>
+ <source>Locked blocks too high, max 1000000 (˜4 yrs)</source>
+ <translation>Låsta block för högt, max 1000000 (˜~4 år)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3258"/>
+ <source>usage: get_tx_proof &lt;txid> &lt;dest_address> [&lt;tx_key>]</source>
+ <translation>användning: get_tx_proof &lt;txid> &lt;måladress> [&lt;tx_key>]</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3289"/>
+ <source>failed to parse tx_key</source>
+ <translation>det gick inte att parsa tx_nyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3298"/>
+ <source>Tx secret key was found for the given txid, but you&apos;ve also provided another tx secret key which doesn&apos;t match the found one.</source>
+ <translation>Hemlig transaktionsnyckel hittades för det givna txid, men du har också angivit en annan hemlig transaktionsnyckel som inte matchar den hittade nyckeln.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3306"/>
+ <source>Tx secret key wasn&apos;t found in the wallet file. Provide it as the optional third parameter if you have it elsewhere.</source>
+ <translation>Den hemliga transaktionsnyckeln kunde inte hittas i plånboksfilen. Ange den som den valfria tredje parametern om du har den någon annanstans.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3330"/>
+ <source>Signature: </source>
+ <translation>Signatur: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3508"/>
+ <source>usage: check_tx_proof &lt;txid> &lt;address> &lt;signature></source>
+ <translation>användning: check_tx_proof &lt;txid> &lt;adress> &lt;signatur></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3539"/>
+ <source>Signature header check error</source>
+ <translation>Fel vid kontroll av signaturhuvud</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3550"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3555"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3560"/>
+ <source>Signature decoding error</source>
+ <translation>nFel vid avkodning av signatur</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3602"/>
+ <source>Tx pubkey was not found</source>
+ <translation>Transaktionens öppna nyckel kunde inte hittas</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3609"/>
+ <source>Good signature</source>
+ <translation>Bra signatur</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3613"/>
+ <source>Bad signature</source>
+ <translation>Dålig signatur</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3621"/>
+ <source>failed to generate key derivation</source>
+ <translation>det gick inte att skapa nyckelhärledning</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3994"/>
+ <source>usage: integrated_address [payment ID]</source>
+ <translation>användning: integrated_address [betalnings-ID]</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4017"/>
+ <source>Integrated address: account %s, payment ID %s</source>
+ <translation>Integrerad adress: konto %s, betalnings-ID %s</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4022"/>
+ <source>Standard address: </source>
+ <translation>Standardadress: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4027"/>
+ <source>failed to parse payment ID or address</source>
+ <translation>det gick inte att parsa betalnings-ID eller adress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4038"/>
+ <source>usage: address_book [(add (&lt;address> [pid &lt;long or short payment id>])|&lt;integrated address> [&lt;description possibly with whitespaces>])|(delete &lt;index>)]</source>
+ <translation>användning: address_book [(add (&lt;adress> [pid &lt;långt eller kort betalnings-ID>])|&lt;Integrerad adress> [&lt;beskrivning eventuellt med blanktecken>])|(delete &lt;index>)]</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4070"/>
+ <source>failed to parse payment ID</source>
+ <translation>det gick inte att parsa betalnings-ID</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4088"/>
+ <source>failed to parse index</source>
+ <translation>det gick inte att parsa index</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4096"/>
+ <source>Address book is empty.</source>
+ <translation>Adressboken är tom.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4102"/>
+ <source>Index: </source>
+ <translation>Index: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4103"/>
+ <source>Address: </source>
+ <translation>Adress: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4104"/>
+ <source>Payment ID: </source>
+ <translation>Betalnings-ID: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4105"/>
+ <source>Description: </source>
+ <translation>Beskrivning: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4115"/>
+ <source>usage: set_tx_note [txid] free text note</source>
+ <translation>användning: set_tx_note [txid] fri textanteckning</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4143"/>
+ <source>usage: get_tx_note [txid]</source>
+ <translation>användning: get_tx_note [txid]</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4193"/>
+ <source>usage: sign &lt;filename></source>
+ <translation>användning: sign &lt;filnamn></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4198"/>
+ <source>wallet is watch-only and cannot sign</source>
+ <translation>plånboken är enbart för granskning och kan inte signera</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4207"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4230"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4374"/>
+ <source>failed to read file </source>
+ <translation>det gick inte att läsa filen </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4219"/>
+ <source>usage: verify &lt;filename> &lt;address> &lt;signature></source>
+ <translation>användning: verify &lt;filnamn> &lt;adress> &lt;signatur></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4246"/>
+ <source>Bad signature from </source>
+ <translation>Dålig signatur från </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4250"/>
+ <source>Good signature from </source>
+ <translation>Bra signatur från </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4259"/>
+ <source>usage: export_key_images &lt;filename></source>
+ <translation>användning: export_key_images &lt;filnamn></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4264"/>
+ <source>wallet is watch-only and cannot export key images</source>
+ <translation>plånboken är enbart för granskning och kan inte exportera nyckelavbildningar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4274"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4346"/>
+ <source>failed to save file </source>
+ <translation>det gick inte att spara fil </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4285"/>
+ <source>Signed key images exported to </source>
+ <translation>Signerade nyckelavbildningar exporterades till </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4293"/>
+ <source>usage: import_key_images &lt;filename></source>
+ <translation>användning: import_key_images &lt;filnamn></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4323"/>
+ <source>usage: export_outputs &lt;filename></source>
+ <translation>användning: export_outputs &lt;filnamn></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4357"/>
+ <source>Outputs exported to </source>
+ <translation>Utgångar exporterades till </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4365"/>
+ <source>usage: import_outputs &lt;filename></source>
+ <translation>användning: import_outputs &lt;filnamn></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2246"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3818"/>
+ <source>amount is wrong: </source>
+ <translation>beloppet är fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2247"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3819"/>
+ <source>expected number from 0 to </source>
+ <translation>förväntades: ett tal från 0 till </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2378"/>
+ <source>Money successfully sent, transaction </source>
+ <translation>Pengar skickades, transaktion </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3141"/>
+ <source>no connection to daemon. Please, make sure daemon is running.</source>
+ <translation>ingen anslutning till daemonen. Se till att daemonen körs.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2420"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2597"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2858"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3171"/>
+ <source>not enough outputs for specified mixin_count</source>
+ <translation>inte tillräckligt många utgångar för angiven mixin_count</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2423"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2600"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2861"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3174"/>
+ <source>output amount</source>
+ <translation>utgångens belopp</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2423"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2600"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2861"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3174"/>
+ <source>found outputs to mix</source>
+ <translation>hittade utgångar att mixa</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2428"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2605"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2866"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3179"/>
+ <source>transaction was not constructed</source>
+ <translation>transaktionen konstruerades inte</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2432"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2609"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2870"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3183"/>
+ <source>transaction %s was rejected by daemon with status: </source>
+ <translation>transaktionen %s avvisades av daemonen med status: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2443"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2620"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2881"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3191"/>
+ <source>one of destinations is zero</source>
+ <translation>ett av målen är noll</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3195"/>
+ <source>Failed to find a suitable way to split transactions</source>
+ <translation>Det gick inte att hitta ett passande sätt att dela upp transaktioner</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2452"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2629"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2890"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3200"/>
+ <source>unknown transfer error: </source>
+ <translation>okänt överföringsfel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2516"/>
+ <source>Sweeping </source>
+ <translation>Sveper upp </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2785"/>
+ <source>Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No)</source>
+ <translation>Sveper upp %s för en total avgift på %s. Är detta okej? (J/Ja/N/Nej)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2555"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="2816"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3129"/>
+ <source>Money successfully sent, transaction: </source>
+ <translation>Pengar skickades, transaktion: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3022"/>
+ <source>Change goes to more than one address</source>
+ <translation>Växel går till mer än en adress</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3047"/>
+ <source>%s change to %s</source>
+ <translation>%s växel till %s</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3050"/>
+ <source>no change</source>
+ <translation>ingen växel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3105"/>
+ <source>Transaction successfully signed to file </source>
+ <translation>Transaktionen signerades till fil </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3226"/>
+ <source>usage: get_tx_key &lt;txid></source>
+ <translation>användning: get_tx_key &lt;transaktions-ID></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3234"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3266"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3354"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3519"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4122"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4150"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4450"/>
+ <source>failed to parse txid</source>
+ <translation>det gick inte att parsa transaktions-id</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3245"/>
+ <source>Tx key: </source>
+ <translation>Tx-nyckel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3250"/>
+ <source>no tx keys found for this txid</source>
+ <translation>inga tx-nycklar kunde hittas för detta txid</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3339"/>
+ <source>usage: check_tx_key &lt;txid> &lt;txkey> &lt;address></source>
+ <translation>användning: check_tx_key &lt;txid> &lt;txnyckel> &lt;adress></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3361"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3368"/>
+ <source>failed to parse tx key</source>
+ <translation>det gick inte att parsa transaktionsnyckeln</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3400"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3573"/>
+ <source>failed to get transaction from daemon</source>
+ <translation>det gick inte att hämta transaktion från daemon</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3411"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3584"/>
+ <source>failed to parse transaction from daemon</source>
+ <translation>det gick inte att parsa transaktion från daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3418"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3591"/>
+ <source>failed to validate transaction from daemon</source>
+ <translation>det gick inte att validera transaktion från daemon</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3423"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3596"/>
+ <source>failed to get the right transaction from daemon</source>
+ <translation>det gick inte att hämta rätt transaktion från daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3385"/>
+ <source>failed to generate key derivation from supplied parameters</source>
+ <translation>det gick inte att skapa nyckelhärledning från angivna parametrar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3471"/>
+ <source>error: </source>
+ <translation>fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3477"/>
+ <source>received</source>
+ <translation>mottaget</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3477"/>
+ <source>in txid</source>
+ <translation>i transaktions-id</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3481"/>
+ <source>received nothing in txid</source>
+ <translation>tog emot ingenting i transaktions-id</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3485"/>
+ <source>WARNING: this transaction is not yet included in the blockchain!</source>
+ <translation>VARNING: denna transaktion är ännu inte inkluderad i blockkedjan!</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3494"/>
+ <source>This transaction has %u confirmations</source>
+ <translation>Transaktionen har %u bekräftelser</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3498"/>
+ <source>WARNING: failed to determine number of confirmations!</source>
+ <translation>VARNING: det gick inte att avgöra antal bekräftelser!</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3661"/>
+ <source>usage: show_transfers [in|out|all|pending|failed] [&lt;min_height> [&lt;max_height>]]</source>
+ <translation>användning: show_transfers [in|out|all|pending|failed] [&lt;min_höjd> [&lt;max_höjd>]]</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3700"/>
+ <source>bad min_height parameter:</source>
+ <translation>dålig parameter för min_height:</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3712"/>
+ <source>bad max_height parameter:</source>
+ <translation>dålig parameter för max_height:</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3760"/>
+ <source>in</source>
+ <translation>in</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3760"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3798"/>
+ <source>out</source>
+ <translation>ut</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3798"/>
+ <source>failed</source>
+ <translation>misslyckades</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3798"/>
+ <source>pending</source>
+ <translation>väntar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3809"/>
+ <source>usage: unspent_outputs [&lt;min_amount> &lt;max_amount>]</source>
+ <translation>användning: unspent_outputs [&lt;min_belopp> &lt;max_belopp>]</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3824"/>
+ <source>&lt;min_amount> should be smaller than &lt;max_amount></source>
+ <translation>&lt;min_belopp> måste vara mindre än &lt;max_belopp></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3856"/>
+ <source>
+Amount: </source>
+ <translation>
+Belopp: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3856"/>
+ <source>, number of keys: </source>
+ <translation>, antal nycklar: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3861"/>
+ <source> </source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3866"/>
+ <source>
+Min block height: </source>
+ <translation>
+Minblockhöjd: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3867"/>
+ <source>
+Max block height: </source>
+ <translation>
+Maxblockhöjd: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3868"/>
+ <source>
+Min amount found: </source>
+ <translation>
+Minbelopp funnet: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3869"/>
+ <source>
+Max amount found: </source>
+ <translation>
+Maxbelopp funnet: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3870"/>
+ <source>
+Total count: </source>
+ <translation>
+Totalt antal: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3910"/>
+ <source>
+Bin size: </source>
+ <translation>
+Storlek för binge: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3911"/>
+ <source>
+Outputs per *: </source>
+ <translation>
+Utgångar per *: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3913"/>
+ <source>count
+ ^
+</source>
+ <translation>antal
+ ^
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3915"/>
+ <source> |</source>
+ <translation> |</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3917"/>
+ <source> +</source>
+ <translation> +</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3917"/>
+ <source>+--> block height
+</source>
+ <translation>+--> blockhöjd
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3918"/>
+ <source> ^</source>
+ <translation> ^</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3918"/>
+ <source>^
+</source>
+ <translation>^
+</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3919"/>
+ <source> </source>
+ <translation></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="3969"/>
+ <source>wallet</source>
+ <translation>plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="420"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4000"/>
+ <source>Random payment ID: </source>
+ <translation>Slumpmässigt betalnings-ID: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4001"/>
+ <source>Matching integrated address: </source>
+ <translation>Matchande integrerad adress: </translation>
+ </message>
+</context>
+<context>
+ <name>sw</name>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="116"/>
+ <source>Generate new wallet and save it to &lt;arg></source>
+ <translation>Skapa ny plånbok och spara den till &lt;arg></translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="117"/>
+ <source>Generate incoming-only wallet from view key</source>
+ <translation>Skapa granskningsplånbok från visningsnyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="118"/>
+ <source>Generate wallet from private keys</source>
+ <translation>Skapa plånbok från privata nycklar</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="120"/>
+ <source>Specify Electrum seed for wallet recovery/creation</source>
+ <translation>Ange Electrum-frö för att återställa/skapa plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="121"/>
+ <source>Recover wallet using Electrum-style mnemonic seed</source>
+ <translation>Återställ plånbok genom användning av minnesfrö (Electrum-typ)</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="122"/>
+ <source>Create non-deterministic view and spend keys</source>
+ <translation>Skapa non-deterministic visnings- och spendernyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="123"/>
+ <source>Enable commands which rely on a trusted daemon</source>
+ <translation>Aktivera kommandon som kräver en betrodd daemon</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="124"/>
+ <source>Allow communicating with a daemon that uses a different RPC version</source>
+ <translation>Tillåt kommunikation med en daemon som använder en annan version av RPC</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="125"/>
+ <source>Restore from specific blockchain height</source>
+ <translation>Återställ från angiven blockkedjehöjd</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="136"/>
+ <source>daemon is busy. Please try again later.</source>
+ <translation>daemonen är upptagen. Försök igen senare.</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="145"/>
+ <source>possibly lost connection to daemon</source>
+ <translation>anslutning till daemonen kan ha tappats</translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="226"/>
+ <source>Error: </source>
+ <translation>Fel: </translation>
+ </message>
+ <message>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4614"/>
+ <source>Failed to initialize wallet</source>
+ <translation>Det gick inte att initiera plånbok</translation>
+ </message>
+</context>
+<context>
+ <name>tools::dns_utils</name>
+ <message>
+ <location filename="../src/common/dns_utils.cpp" line="430"/>
+ <source>DNSSEC validation passed</source>
+ <translation>DNSSEC-validering godkänd</translation>
+ </message>
+ <message>
+ <location filename="../src/common/dns_utils.cpp" line="434"/>
+ <source>WARNING: DNSSEC validation was unsuccessful, this address may not be correct!</source>
+ <translation>VARNING: DNSSEC-verifiering misslyckades, denna adress kanske inte är korrekt!</translation>
+ </message>
+ <message>
+ <location filename="../src/common/dns_utils.cpp" line="437"/>
+ <source>For URL: </source>
+ <translation>För URL: </translation>
+ </message>
+ <message>
+ <location filename="../src/common/dns_utils.cpp" line="439"/>
+ <source> Monero Address = </source>
+ <translation> Monero-adress = </translation>
+ </message>
+ <message>
+ <location filename="../src/common/dns_utils.cpp" line="441"/>
+ <source>Is this OK? (Y/n) </source>
+ <translation>är det OK? (J/n) </translation>
+ </message>
+ <message>
+ <location filename="../src/common/dns_utils.cpp" line="451"/>
+ <source>you have cancelled the transfer request</source>
+ <translation>du har avbrutit överföringsbegäran</translation>
+ </message>
+</context>
+<context>
+ <name>tools::wallet2</name>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="106"/>
+ <source>Use daemon instance at &lt;host>:&lt;port></source>
+ <translation>Använd daemoninstans på &lt;värddator>:&lt;port></translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="107"/>
+ <source>Use daemon instance at host &lt;arg> instead of localhost</source>
+ <translation>Använd daemon-instansen på värddator &lt;arg> istället för localhost</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="460"/>
+ <source>Wallet password</source>
+ <translation>Lösenord för plånboken</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="109"/>
+ <source>Wallet password file</source>
+ <translation>Lösenordsfil för plånboken</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="110"/>
+ <source>Use daemon instance at port &lt;arg> instead of 18081</source>
+ <translation>Använd daemon-instansen på port &lt;arg> istället för 18081</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="112"/>
+ <source>For testnet. Daemon must also be launched with --testnet flag</source>
+ <translation>För testnet. Daemonen måste också startas med flaggan --testnet</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="113"/>
+ <source>Restricts to view-only commands</source>
+ <translation>Begränsar till granskningskommandon</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="152"/>
+ <source>can&apos;t specify daemon host or port more than once</source>
+ <translation>det går inte ange värd eller port för daemonen mer än en gång</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="188"/>
+ <source>can&apos;t specify more than one of --password and --password-file</source>
+ <translation>det går inte att ange mer än en av --password och --password-file</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="204"/>
+ <source>the password file specified could not be read</source>
+ <translation>det gick inte att läsa angiven lösenordsfil</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="460"/>
+ <source>Enter new wallet password</source>
+ <translation>Ange nytt lösenord för plånboken</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="464"/>
+ <source>failed to read wallet password</source>
+ <translation>det gick inte att läsa lösenord för plånboken</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="227"/>
+ <source>Failed to load file </source>
+ <translation>Det gick inte att läsa in fil </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="108"/>
+ <source>Wallet password (escape/quote as needed)</source>
+ <translation>Lösenord för plånboken (använd escape-sekvenser eller citattecken efter behov)</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="111"/>
+ <source>Specify username[:password] for daemon RPC client</source>
+ <translation>Ange användarnamn[:lösenord] för RPC-klient till daemonen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="233"/>
+ <source>Failed to parse JSON</source>
+ <translation>Det gick inte att parsa JSON</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="240"/>
+ <source>Version %u too new, we can only grok up to %u</source>
+ <translation>Version %u är för ny, vi förstår bara upp till %u</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="258"/>
+ <source>failed to parse view key secret key</source>
+ <translation>det gick inte att parsa hemlig visningsnyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="264"/>
+ <location filename="../src/wallet/wallet2.cpp" line="331"/>
+ <location filename="../src/wallet/wallet2.cpp" line="373"/>
+ <source>failed to verify view key secret key</source>
+ <translation>det gick inte att verifiera hemlig visningsnyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="276"/>
+ <source>failed to parse spend key secret key</source>
+ <translation>det gick inte att parsa spendernyckel hemlig nyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="282"/>
+ <location filename="../src/wallet/wallet2.cpp" line="343"/>
+ <location filename="../src/wallet/wallet2.cpp" line="394"/>
+ <source>failed to verify spend key secret key</source>
+ <translation>det gick inte att verifiera spendernyckel hemlig nyckel</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="295"/>
+ <source>Electrum-style word list failed verification</source>
+ <translation>det gick inte att verifiera ordlista av Electrum-typ</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="306"/>
+ <source>At least one of Electrum-style word list and private view key must be specified</source>
+ <translation>Åtminstone en av ordlista av Electrum-typ och privat visningsnyckel måste anges</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="311"/>
+ <source>Both Electrum-style word list and private key(s) specified</source>
+ <translation>Både ordlista av Electrum-typ och privat nyckel har angivits</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="324"/>
+ <source>invalid address</source>
+ <translation>ogiltig adress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="335"/>
+ <source>view key does not match standard address</source>
+ <translation>visningsnyckel matchar inte standardadress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="347"/>
+ <source>spend key does not match standard address</source>
+ <translation>spendernyckel matchar inte standardadress</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="356"/>
+ <source>Cannot create deprecated wallets from JSON</source>
+ <translation>Det går inte att skapa inaktuella plånböcker från JSON</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="403"/>
+ <source>failed to generate new wallet: </source>
+ <translation>det gick inte att skapa ny plånbok: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet2.cpp" line="5205"/>
+ <source>failed to read file </source>
+ <translation>det gick inte att läsa filen </translation>
+ </message>
+</context>
+<context>
+ <name>tools::wallet_rpc_server</name>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="151"/>
+ <source>Daemon is local, assuming trusted</source>
+ <translation>Daemonen är lokal, utgår från att den är betrodd</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="171"/>
+ <source>Cannot specify --</source>
+ <translation>Det går inte att ange --</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="171"/>
+ <source> and --</source>
+ <translation> och --</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="198"/>
+ <source>Failed to create file </source>
+ <translation>Det gick inte att skapa fil </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="198"/>
+ <source>. Check permissions or remove file</source>
+ <translation>. Kontrollera behörigheter eller ta bort filen</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="209"/>
+ <source>Error writing to file </source>
+ <translation>Fel vid skrivning till fil </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="212"/>
+ <source>RPC username/password is stored in file </source>
+ <translation>Användarnamn/lösenord för RPC har sparats i fil </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1748"/>
+ <source>Can&apos;t specify more than one of --wallet-file and --generate-from-json</source>
+ <translation>Det går inte att ange mer än en av --wallet-file och --generate-from-json</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1760"/>
+ <source>Must specify --wallet-file or --generate-from-json or --wallet-dir</source>
+ <translation>Måste ange --wallet-file eller --generate-from-json eller --wallet-dir</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1764"/>
+ <source>Loading wallet...</source>
+ <translation>Läser in plånbok …</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1789"/>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1814"/>
+ <source>Storing wallet...</source>
+ <translation>Sparar plånbok …</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1791"/>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1816"/>
+ <source>Stored ok</source>
+ <translation>Sparad ok</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1794"/>
+ <source>Loaded ok</source>
+ <translation>Inläst ok</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1798"/>
+ <source>Wallet initialization failed: </source>
+ <translation>Det gick inte att initiera plånbok: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1805"/>
+ <source>Failed to initialize wallet rpc server</source>
+ <translation>Det gick inte att initiera RPC-servern för plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1809"/>
+ <source>Starting wallet rpc server</source>
+ <translation>Startar RPC-servern för plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1811"/>
+ <source>Stopped wallet rpc server</source>
+ <translation>Stoppade RPC-servern för plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1820"/>
+ <source>Failed to store wallet: </source>
+ <translation>Det gick inte att spara plånbok: </translation>
+ </message>
+</context>
+<context>
+ <name>wallet_args</name>
+ <message>
+ <location filename="../src/wallet/wallet_rpc_server.cpp" line="1715"/>
+ <location filename="../src/simplewallet/simplewallet.cpp" line="4580"/>
+ <source>Wallet options</source>
+ <translation>Alternativ för plånbok</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="59"/>
+ <source>Generate wallet from JSON format file</source>
+ <translation>Skapa plånbok från fil i JSON-format</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="63"/>
+ <source>Use wallet &lt;arg></source>
+ <translation>Använd plånbok &lt;arg></translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="87"/>
+ <source>Max number of threads to use for a parallel job</source>
+ <translation>Max antal trådar att använda för ett parallellt jobb</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="88"/>
+ <source>Specify log file</source>
+ <translation>Ange loggfil</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="89"/>
+ <source>Config file</source>
+ <translation>Konfigurationsfil</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="98"/>
+ <source>General options</source>
+ <translation>Allmänna alternativ</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="128"/>
+ <source>Can&apos;t find config file </source>
+ <translation>Det gick inte att hitta konfigurationsfilen </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="172"/>
+ <source>Logging to: </source>
+ <translation>Loggar till: </translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="173"/>
+ <source>Logging to %s</source>
+ <translation>Loggar till %s</translation>
+ </message>
+ <message>
+ <location filename="../src/wallet/wallet_args.cpp" line="153"/>
+ <source>Usage:</source>
+ <translation>Användning:</translation>
+ </message>
+</context>
+</TS>
diff --git a/utils/build_scripts/android32.Dockerfile b/utils/build_scripts/android32.Dockerfile
index 37d012202..20b846aa1 100644
--- a/utils/build_scripts/android32.Dockerfile
+++ b/utils/build_scripts/android32.Dockerfile
@@ -80,7 +80,7 @@ RUN git clone https://github.com/zeromq/zeromq4-1.git \
&& CC=clang CXX=clang++ ./configure --host=arm-none-linux-gnueabi \
&& make
-RUN ln -s /opt/android/openssl/libcrypto.a /opt/android/openssl/libssl.a /opt/android/toolchain-arm/arm-linux-androideabi/lib/armv7-a
+RUN ln -s /opt/android/openssl/libcrypto.a /opt/android/openssl/libssl.a ${TOOLCHAIN_DIR}/arm-linux-androideabi/lib/armv7-a
RUN git clone https://github.com/monero-project/monero.git \
&& cd monero \
diff --git a/utils/build_scripts/android64.Dockerfile b/utils/build_scripts/android64.Dockerfile
index 70c3c2b41..83bcbad89 100644
--- a/utils/build_scripts/android64.Dockerfile
+++ b/utils/build_scripts/android64.Dockerfile
@@ -79,7 +79,7 @@ RUN git clone https://github.com/zeromq/zeromq4-1.git \
&& CC=clang CXX=clang++ ./configure --host=aarch64-linux-android \
&& make
-RUN ln -s /opt/android/openssl/libcrypto.a /opt/android/openssl/libssl.a /opt/android/toolchain-arm/aarch64-linux-android/lib
+RUN ln -s /opt/android/openssl/libcrypto.a /opt/android/openssl/libssl.a ${TOOLCHAIN_DIR}/aarch64-linux-android/lib
RUN git clone https://github.com/monero-project/monero.git \
&& cd monero \