Compare commits
114 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6e63ef260 | |||
| 298208d92b | |||
| d7b74a4fb0 | |||
| f719b74cd1 | |||
| 1d597ad910 | |||
| 4f6eea9021 | |||
| 076254d113 | |||
| daa1376370 | |||
| eed63cef36 | |||
| dcdbf7ebcf | |||
| c18cdd3623 | |||
| 13978a9887 | |||
| fd869a7b64 | |||
| c8c7c40ac8 | |||
| 21ab1de89f | |||
| 699e82c282 | |||
| 9ec4ce36c7 | |||
| 9ca9f1214a | |||
| d5b78c08b6 | |||
| f59b1d5fb5 | |||
| 4a9ae3eb8b | |||
| 837c9aec22 | |||
| af46a291ad | |||
| 25588de40c | |||
| 7fd140e4f7 | |||
| c1776be54f | |||
| 30bc575505 | |||
| aa408d1c72 | |||
| c8895ccbb7 | |||
| 975d390d00 | |||
| 332b9734ff | |||
| b5667c9f6c | |||
| d8137dc523 | |||
| c6e1d7bcdf | |||
| 6d5e2106b3 | |||
| afec439953 | |||
| 25670398b1 | |||
| fe6dda9453 | |||
| 8fef32e45c | |||
| 7f1a83b852 | |||
| 89fe0e1c81 | |||
| b06ccc0416 | |||
| 83fa752a84 | |||
| 7ecdc53e11 | |||
| 32ab89aa86 | |||
| 5d2dd7a328 | |||
| f3de67bc21 | |||
| 51057105b9 | |||
| 54cf799f0f | |||
| 3c7eec152c | |||
| 1128146c49 | |||
| c2295f55b8 | |||
| 31b2572ec7 | |||
| 0add7ec1cd | |||
| 2107337999 | |||
| f4e34d50cf | |||
| a4ffad75ac | |||
| 024783f73a | |||
| db686707cb | |||
| 5767e6db90 | |||
| cb296b39bd | |||
| 57f7c2e53f | |||
| 531069859f | |||
| 00b3502749 | |||
| e685f52e25 | |||
| 00253b717c | |||
| 7d67a2dde0 | |||
| 36dfd41e01 | |||
| bcd7f63a54 | |||
| 3a477a54a2 | |||
| 218a109677 | |||
| b8bc4d77b7 | |||
| b39ee13d70 | |||
| a99d6e56b6 | |||
| 5804add75b | |||
| 75e9e7b39a | |||
| a87eca5e7d | |||
| 8c8f3d73b5 | |||
| 0fc927dfba | |||
| d3e582e517 | |||
| e42bb297b8 | |||
| 0443cccb5d | |||
| b42d08995e | |||
| 138092ddc9 | |||
| 4ddde36c50 | |||
| 0873f3193a | |||
| cbeaeb904b | |||
| 355be543c7 | |||
| 6cea8ca895 | |||
| e08d37fc7b | |||
| 1c14b7b3b2 | |||
| 31ae533d6d | |||
| d5be31ee21 | |||
| adcbcd8f8b | |||
| ba3c627c57 | |||
| 07b50c42dd | |||
| ba60541f3e | |||
| 5c3e84b6ae | |||
| e35bbb1e88 | |||
| fb9ef24267 | |||
| ee8d740cba | |||
| e0e2eb2bf5 | |||
| ecedaf2975 | |||
| 94897cf8f7 | |||
| e38f3dbfb2 | |||
| a4cdcd9bd0 | |||
| 42ee309292 | |||
| f0b867b13d | |||
| a436c36256 | |||
| cf4461f40b | |||
| 905cc07c8b | |||
| 3bb748ad94 | |||
| a569483c19 | |||
| 55e4007c48 |
@@ -36,10 +36,6 @@ with additional exclusive IPv4 address(es).
|
||||
|
||||
## Usage
|
||||
|
||||
Anonymity networks have no seed nodes (the feature is still considered
|
||||
experimental), so a user must specify an address. If configured properly,
|
||||
additional peers can be found through typical p2p peerlist sharing.
|
||||
|
||||
### Outbound Connections
|
||||
|
||||
Connecting to an anonymous address requires the command line option
|
||||
@@ -54,8 +50,9 @@ separate process. On most systems the configuration will look like:
|
||||
which tells `monerod` that ".onion" p2p addresses can be forwarded to a socks
|
||||
proxy at IP 127.0.0.1 port 9050 with a max of 10 outgoing connections and
|
||||
".b32.i2p" p2p addresses can be forwarded to a socks proxy at IP 127.0.0.1 port
|
||||
9000 with the default max outgoing connections. Since there are no seed nodes
|
||||
for anonymity connections, peers must be manually specified:
|
||||
9000 with the default max outgoing connections.
|
||||
|
||||
If desired, peers can be manually specified:
|
||||
|
||||
```
|
||||
--add-exclusive-node rveahdfho7wo4b2m.onion:28083
|
||||
|
||||
+12
-1
@@ -501,6 +501,17 @@ endif()
|
||||
# Trezor support check
|
||||
include(CheckTrezor)
|
||||
|
||||
# As of OpenBSD 6.8, -march=<anything> breaks the build
|
||||
function(set_default_arch)
|
||||
if (OPENBSD)
|
||||
set(ARCH default)
|
||||
else()
|
||||
set(ARCH native)
|
||||
endif()
|
||||
|
||||
set(ARCH ${ARCH} CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all")
|
||||
endfunction()
|
||||
|
||||
if(MSVC)
|
||||
add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__")
|
||||
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline")
|
||||
@@ -514,7 +525,7 @@ if(MSVC)
|
||||
else()
|
||||
include(TestCXXAcceptsFlag)
|
||||
if (NOT ARCH)
|
||||
set(ARCH native CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all")
|
||||
set_default_arch()
|
||||
endif()
|
||||
message(STATUS "Building on ${CMAKE_SYSTEM_PROCESSOR} for ${ARCH}")
|
||||
if(ARCH STREQUAL "default")
|
||||
|
||||
@@ -134,8 +134,8 @@ Dates are provided in the format YYYY-MM-DD.
|
||||
| 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format
|
||||
| 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format
|
||||
| 1978433 | 2019-11-30* | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
|
||||
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.1.7 | New CLSAG transaction format
|
||||
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.1.7 | forbid old MLSAG transaction format
|
||||
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.2.0 | New CLSAG transaction format
|
||||
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.2.0 | forbid old MLSAG transaction format
|
||||
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
|
||||
|
||||
X's indicate that these details have not been determined as of commit date.
|
||||
@@ -295,7 +295,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
|
||||
```bash
|
||||
git clone https://github.com/monero-project/monero.git
|
||||
cd monero
|
||||
git checkout tags/v0.17.1.7
|
||||
git checkout tags/v0.17.2.0
|
||||
```
|
||||
|
||||
* Build:
|
||||
@@ -412,10 +412,10 @@ application.
|
||||
cd monero
|
||||
```
|
||||
|
||||
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.1.7'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.17.2.0'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.17.1.7
|
||||
git checkout v0.17.2.0
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package=openssl
|
||||
$(package)_version=1.1.1i
|
||||
$(package)_version=1.1.1k
|
||||
$(package)_download_path=https://www.openssl.org/source
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=e8be6a35fe41d10603c3cc635e93289ed00bf34b79671a3a4de64fcee00d5242
|
||||
$(package)_sha256_hash=892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
PACKAGE=qt
|
||||
$(package)_version=5.7.1
|
||||
$(package)_download_path=http://linorg.usp.br/Qt/archive/qt/5.7/5.7.1/submodules
|
||||
$(package)_suffix=opensource-src-$($(package)_version).tar.gz
|
||||
$(package)_version=5.15.1
|
||||
$(package)_download_path=https://download.qt.io/official_releases/qt/5.15/$($(package)_version)/submodules
|
||||
$(package)_suffix=everywhere-src-$($(package)_version).tar.xz
|
||||
$(package)_file_name=qtbase-$($(package)_suffix)
|
||||
$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410
|
||||
$(package)_sha256_hash=33960404d579675b7210de103ed06a72613bfc4305443e278e2d32a3eb1f3d8c
|
||||
$(package)_build_subdir=qtbase
|
||||
$(package)_qt_libs=corelib
|
||||
$(package)_patches=pidlist_absolute.patch fix_qt_pkgconfig.patch qfixed-coretext.patch
|
||||
$(package)_patches=fix_qt_pkgconfig.patch fix_no_printer.patch fix_rcc_determinism.patch no-xlib.patch
|
||||
|
||||
$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix)
|
||||
$(package)_qttranslations_sha256_hash=3a15aebd523c6d89fb97b2d3df866c94149653a26d27a00aac9b6d3020bc5a1d
|
||||
$(package)_qttranslations_sha256_hash=46e0c0e3a511fbcc803a4146204062e47f6ed43b34d98a3c27372a03b8746bd8
|
||||
|
||||
$(package)_qttools_file_name=qttools-$($(package)_suffix)
|
||||
$(package)_qttools_sha256_hash=22d67de915cb8cd93e16fdd38fa006224ad9170bd217c2be1e53045a8dd02f0f
|
||||
$(package)_qttools_sha256_hash=c98ee5f0f980bf68cbf0c94d62434816a92441733de50bd9adbe9b9055f03498
|
||||
|
||||
$(package)_extra_sources = $($(package)_qttranslations_file_name)
|
||||
$(package)_extra_sources += $($(package)_qttools_file_name)
|
||||
@@ -24,28 +24,26 @@ $(package)_config_opts += -bindir $(build_prefix)/bin
|
||||
$(package)_config_opts += -c++std c++11
|
||||
$(package)_config_opts += -confirm-license
|
||||
$(package)_config_opts += -dbus-runtime
|
||||
$(package)_config_opts += -no-alsa
|
||||
$(package)_config_opts += -no-audio-backend
|
||||
$(package)_config_opts += -hostprefix $(build_prefix)
|
||||
$(package)_config_opts += -no-compile-examples
|
||||
$(package)_config_opts += -no-cups
|
||||
$(package)_config_opts += -no-egl
|
||||
$(package)_config_opts += -no-eglfs
|
||||
$(package)_config_opts += -no-feature-style-windowsmobile
|
||||
$(package)_config_opts += -no-feature-style-windowsce
|
||||
$(package)_config_opts += -no-evdev
|
||||
$(package)_config_opts += -no-gui
|
||||
$(package)_config_opts += -no-freetype
|
||||
$(package)_config_opts += -no-gif
|
||||
$(package)_config_opts += -no-glib
|
||||
$(package)_config_opts += -no-gstreamer
|
||||
$(package)_config_opts += -no-icu
|
||||
$(package)_config_opts += -no-ico
|
||||
$(package)_config_opts += -no-iconv
|
||||
$(package)_config_opts += -no-kms
|
||||
$(package)_config_opts += -no-linuxfb
|
||||
$(package)_config_opts += -no-libjpeg
|
||||
$(package)_config_opts += -no-libudev
|
||||
$(package)_config_opts += -no-mitshm
|
||||
$(package)_config_opts += -no-mtdev
|
||||
$(package)_config_opts += -no-pulseaudio
|
||||
$(package)_config_opts += -no-openvg
|
||||
$(package)_config_opts += -no-reduce-relocations
|
||||
$(package)_config_opts += -no-qml-debug
|
||||
$(package)_config_opts += -no-sql-db2
|
||||
$(package)_config_opts += -no-sql-ibase
|
||||
$(package)_config_opts += -no-sql-oci
|
||||
@@ -56,8 +54,6 @@ $(package)_config_opts += -no-sql-psql
|
||||
$(package)_config_opts += -no-sql-sqlite
|
||||
$(package)_config_opts += -no-sql-sqlite2
|
||||
$(package)_config_opts += -no-use-gold-linker
|
||||
$(package)_config_opts += -no-xinput2
|
||||
$(package)_config_opts += -no-xrender
|
||||
$(package)_config_opts += -nomake examples
|
||||
$(package)_config_opts += -nomake tests
|
||||
$(package)_config_opts += -opensource
|
||||
@@ -65,25 +61,46 @@ $(package)_config_opts += -no-openssl
|
||||
$(package)_config_opts += -optimized-qmake
|
||||
$(package)_config_opts += -pch
|
||||
$(package)_config_opts += -pkg-config
|
||||
$(package)_config_opts += -prefix $(host_prefix)
|
||||
$(package)_config_opts += -no-libpng
|
||||
$(package)_config_opts += -no-libjpeg
|
||||
$(package)_config_opts += -qt-pcre
|
||||
$(package)_config_opts += -qt-harfbuzz
|
||||
$(package)_config_opts += -no-zlib
|
||||
$(package)_config_opts += -reduce-exports
|
||||
$(package)_config_opts += -static
|
||||
$(package)_config_opts += -silent
|
||||
$(package)_config_opts += -v
|
||||
$(package)_config_opts += -no-feature-printer
|
||||
$(package)_config_opts += -no-feature-bearermanagement
|
||||
$(package)_config_opts += -no-feature-colordialog
|
||||
$(package)_config_opts += -no-feature-dial
|
||||
$(package)_config_opts += -no-feature-filesystemwatcher
|
||||
$(package)_config_opts += -no-feature-fontcombobox
|
||||
$(package)_config_opts += -no-feature-ftp
|
||||
$(package)_config_opts += -no-feature-image_heuristic_mask
|
||||
$(package)_config_opts += -no-feature-keysequenceedit
|
||||
$(package)_config_opts += -no-feature-lcdnumber
|
||||
$(package)_config_opts += -no-feature-pdf
|
||||
$(package)_config_opts += -no-feature-printdialog
|
||||
$(package)_config_opts += -no-gui
|
||||
$(package)_config_opts += -no-freetype
|
||||
$(package)_config_opts += -no-sm
|
||||
$(package)_config_opts += -no-fontconfig
|
||||
$(package)_config_opts += -no-opengl
|
||||
$(package)_config_opts += -no-xkb
|
||||
$(package)_config_opts += -no-xcb
|
||||
$(package)_config_opts += -no-xshape
|
||||
$(package)_build_env = QT_RCC_TEST=1
|
||||
$(package)_config_opts += -no-feature-printer
|
||||
$(package)_config_opts += -no-feature-printpreviewdialog
|
||||
$(package)_config_opts += -no-feature-printpreviewwidget
|
||||
$(package)_config_opts += -no-feature-sessionmanager
|
||||
$(package)_config_opts += -no-feature-sql
|
||||
$(package)_config_opts += -no-feature-statemachine
|
||||
$(package)_config_opts += -no-feature-syntaxhighlighter
|
||||
$(package)_config_opts += -no-feature-textbrowser
|
||||
$(package)_config_opts += -no-feature-textodfwriter
|
||||
$(package)_config_opts += -no-feature-topleveldomain
|
||||
$(package)_config_opts += -no-feature-udpsocket
|
||||
$(package)_config_opts += -no-feature-undocommand
|
||||
$(package)_config_opts += -no-feature-undogroup
|
||||
$(package)_config_opts += -no-feature-undostack
|
||||
$(package)_config_opts += -no-feature-undoview
|
||||
$(package)_config_opts += -no-feature-vnc
|
||||
$(package)_config_opts += -no-feature-wizard
|
||||
$(package)_config_opts_linux = -no-fontconfig
|
||||
$(package)_config_opts_linux += -no-opengl
|
||||
$(package)_config_opts_linux += -no-xcb
|
||||
$(package)_config_opts_linux += -no-feature-xlib
|
||||
endef
|
||||
|
||||
define $(package)_fetch_cmds
|
||||
@@ -108,14 +125,24 @@ endef
|
||||
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
sed -i.old "s|FT_Get_Font_Format|FT_Get_X11_Font_Format|" qtbase/src/platformsupport/fontdatabases/freetype/qfontengine_ft.cpp && \
|
||||
sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \
|
||||
sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \
|
||||
patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \
|
||||
patch -p1 < $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \
|
||||
patch -p1 < $($(package)_patch_dir)/qfixed-coretext.patch && \
|
||||
sed -i.old "s/src_plugins.depends = src_sql src_network/src_plugins.depends = src_network/" qtbase/src/src.pro && \
|
||||
cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/bitcoin-linux-g++ && \
|
||||
sed -i.old "s/arm-linux-gnueabi-/$(host)-/g" qtbase/mkspecs/bitcoin-linux-g++/qmake.conf && \
|
||||
patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \
|
||||
patch -p1 -i $($(package)_patch_dir)/fix_no_printer.patch && \
|
||||
echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
|
||||
echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
|
||||
echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf
|
||||
echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf && \
|
||||
patch -p1 -i $($(package)_patch_dir)/no-xlib.patch && \
|
||||
echo "QMAKE_LINK_OBJECT_MAX = 10" >> qtbase/mkspecs/win32-g++/qmake.conf && \
|
||||
echo "QMAKE_LINK_OBJECT_SCRIPT = object_script" >> qtbase/mkspecs/win32-g++/qmake.conf && \
|
||||
sed -i.old "s|QMAKE_CFLAGS += |!host_build: QMAKE_CFLAGS = $($(package)_cflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \
|
||||
sed -i.old "s|QMAKE_CXXFLAGS += |!host_build: QMAKE_CXXFLAGS = $($(package)_cxxflags) $($(package)_cppflags) |" qtbase/mkspecs/win32-g++/qmake.conf && \
|
||||
sed -i.old "0,/^QMAKE_LFLAGS_/s|^QMAKE_LFLAGS_|!host_build: QMAKE_LFLAGS = $($(package)_ldflags)\n&|" qtbase/mkspecs/win32-g++/qmake.conf && \
|
||||
sed -i.old "s/LIBRARY_PATH/(CROSS_)?\0/g" qtbase/mkspecs/features/toolchain.prf
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
--- x/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h
|
||||
+++ y/qtbase/src/plugins/platforms/cocoa/qprintengine_mac_p.h
|
||||
@@ -52,6 +52,7 @@
|
||||
//
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
+#include <qpa/qplatformprintdevice.h>
|
||||
|
||||
#ifndef QT_NO_PRINTER
|
||||
|
||||
--- x/qtbase/src/plugins/plugins.pro
|
||||
+++ y/qtbase/src/plugins/plugins.pro
|
||||
@@ -9,6 +9,3 @@ qtHaveModule(gui) {
|
||||
!android:qtConfig(library): SUBDIRS *= generic
|
||||
}
|
||||
qtHaveModule(widgets): SUBDIRS += styles
|
||||
-
|
||||
-!winrt:qtHaveModule(printsupport): \
|
||||
- SUBDIRS += printsupport
|
||||
@@ -1,11 +1,11 @@
|
||||
--- old/qtbase/mkspecs/features/qt_module.prf
|
||||
+++ new/qtbase/mkspecs/features/qt_module.prf
|
||||
@@ -245,7 +245,7 @@
|
||||
@@ -269,7 +269,7 @@ load(qt_installs)
|
||||
load(qt_targets)
|
||||
|
||||
# this builds on top of qt_common
|
||||
-!internal_module:!lib_bundle:if(unix|mingw) {
|
||||
+unix|mingw {
|
||||
-!internal_module:if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) {
|
||||
+if(unix|mingw):!if(darwin:debug_and_release:CONFIG(debug, debug|release)) {
|
||||
CONFIG += create_pc
|
||||
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
|
||||
host_build: \
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
--- old/qtbase/src/tools/rcc/rcc.cpp
|
||||
+++ new/qtbase/src/tools/rcc/rcc.cpp
|
||||
@@ -207,7 +207,11 @@ void RCCFileInfo::writeDataInfo(RCCResourceLibrary &lib)
|
||||
if (lib.formatVersion() >= 2) {
|
||||
// last modified time stamp
|
||||
const QDateTime lastModified = m_fileInfo.lastModified();
|
||||
- lib.writeNumber8(quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0));
|
||||
+ quint64 lastmod = quint64(lastModified.isValid() ? lastModified.toMSecsSinceEpoch() : 0);
|
||||
+ static const quint64 sourceDate = 1000 * qgetenv("QT_RCC_SOURCE_DATE_OVERRIDE").toULongLong();
|
||||
+ if (sourceDate != 0)
|
||||
+ lastmod = sourceDate;
|
||||
+ lib.writeNumber8(lastmod);
|
||||
if (text || pass1)
|
||||
lib.writeChar('\n');
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
From 9563cef873ae82e06f60708d706d054717e801ce Mon Sep 17 00:00:00 2001
|
||||
From: Carl Dong <contact@carldong.me>
|
||||
Date: Thu, 18 Jul 2019 17:22:05 -0400
|
||||
Subject: [PATCH] Wrap xlib related code blocks in #if's
|
||||
|
||||
They are not necessary to compile QT.
|
||||
---
|
||||
qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp
|
||||
index 7c62c2e2b3..c05c6c0a07 100644
|
||||
--- a/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp
|
||||
+++ b/qtbase/src/plugins/platforms/xcb/qxcbcursor.cpp
|
||||
@@ -49,7 +49,9 @@
|
||||
#include <QtGui/QWindow>
|
||||
#include <QtGui/QBitmap>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
+#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
|
||||
#include <X11/cursorfont.h>
|
||||
+#endif
|
||||
#include <xcb/xfixes.h>
|
||||
#include <xcb/xcb_image.h>
|
||||
|
||||
@@ -391,6 +393,7 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *window)
|
||||
xcb_flush(xcb_connection());
|
||||
}
|
||||
|
||||
+#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
|
||||
static int cursorIdForShape(int cshape)
|
||||
{
|
||||
int cursorId = 0;
|
||||
@@ -444,6 +447,7 @@ static int cursorIdForShape(int cshape)
|
||||
}
|
||||
return cursorId;
|
||||
}
|
||||
+#endif
|
||||
|
||||
xcb_cursor_t QXcbCursor::createNonStandardCursor(int cshape)
|
||||
{
|
||||
@@ -556,7 +560,9 @@ static xcb_cursor_t loadCursor(void *dpy, int cshape)
|
||||
xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
|
||||
{
|
||||
xcb_connection_t *conn = xcb_connection();
|
||||
+#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
|
||||
int cursorId = cursorIdForShape(cshape);
|
||||
+#endif
|
||||
xcb_cursor_t cursor = XCB_NONE;
|
||||
|
||||
// Try Xcursor first
|
||||
@@ -586,6 +592,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
|
||||
// Non-standard X11 cursors are created from bitmaps
|
||||
cursor = createNonStandardCursor(cshape);
|
||||
|
||||
+#if QT_CONFIG(xcb_xlib) && QT_CONFIG(library)
|
||||
// Create a glpyh cursor if everything else failed
|
||||
if (!cursor && cursorId) {
|
||||
cursor = xcb_generate_id(conn);
|
||||
@@ -593,6 +600,7 @@ xcb_cursor_t QXcbCursor::createFontCursor(int cshape)
|
||||
cursorId, cursorId + 1,
|
||||
0xFFFF, 0xFFFF, 0xFFFF, 0, 0, 0);
|
||||
}
|
||||
+#endif
|
||||
|
||||
if (cursor && cshape >= 0 && cshape < Qt::LastCursor && connection()->hasXFixes()) {
|
||||
const char *name = cursorNames[cshape].front();
|
||||
---
|
||||
2.22.0
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
diff -dur old/qtbase/src/plugins/platforms/windows/qwindowscontext.h new/qtbase/src/plugins/platforms/windows/qwindowscontext.h
|
||||
--- old/qtbase/src/plugins/platforms/windows/qwindowscontext.h
|
||||
+++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h
|
||||
@@ -136,10 +136,18 @@
|
||||
inline void init();
|
||||
|
||||
typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **);
|
||||
+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
|
||||
+ typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, ITEMIDLIST **);
|
||||
+#else
|
||||
typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, PIDLIST_ABSOLUTE *);
|
||||
+#endif
|
||||
typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *);
|
||||
typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **);
|
||||
+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
|
||||
+ typedef HRESULT (WINAPI *SHCreateItemFromIDList)(const ITEMIDLIST *, REFIID, void **);
|
||||
+#else
|
||||
typedef HRESULT (WINAPI *SHCreateItemFromIDList)(PCIDLIST_ABSOLUTE, REFIID, void **);
|
||||
+#endif
|
||||
|
||||
SHCreateItemFromParsingName sHCreateItemFromParsingName;
|
||||
SHGetKnownFolderIDList sHGetKnownFolderIDList;
|
||||
diff -dur old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
|
||||
--- old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
|
||||
+++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
|
||||
@@ -1016,7 +1016,11 @@
|
||||
qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path();
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
+#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3)
|
||||
+ ITEMIDLIST *idList;
|
||||
+#else
|
||||
PIDLIST_ABSOLUTE idList;
|
||||
+#endif
|
||||
HRESULT hr = QWindowsContext::shell32dll.sHGetKnownFolderIDList(uuid, 0, 0, &idList);
|
||||
if (FAILED(hr)) {
|
||||
qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString()));
|
||||
@@ -1,34 +0,0 @@
|
||||
From dbdd5f0ffbce52c8b789ed09f1aa3f1da6c02e23 Mon Sep 17 00:00:00 2001
|
||||
From: Gabriel de Dietrich <gabriel.dedietrich@qt.io>
|
||||
Date: Fri, 30 Mar 2018 11:58:16 -0700
|
||||
Subject: [PATCH] QCoreTextFontEngine: Fix build with Xcode 9.3
|
||||
|
||||
Apple LLVM version 9.1.0 (clang-902.0.39.1)
|
||||
|
||||
Error message:
|
||||
|
||||
.../qfontengine_coretext.mm:827:20: error: qualified reference to
|
||||
'QFixed' is a constructor name rather than a type in this context
|
||||
return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont)));
|
||||
|
||||
Change-Id: Iebe26b3b087a16b10664208fc8851cbddb47f043
|
||||
Reviewed-by: Konstantin Ritt <ritt.ks@gmail.com>
|
||||
---
|
||||
src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git old/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm new/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
index 25ff69d877d..98b753eff96 100644
|
||||
--- old/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
+++ new/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
|
||||
@@ -824,7 +824,7 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gl
|
||||
|
||||
QFixed QCoreTextFontEngine::emSquareSize() const
|
||||
{
|
||||
- return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont)));
|
||||
+ return QFixed(int(CTFontGetUnitsPerEm(ctfont)));
|
||||
}
|
||||
|
||||
QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const
|
||||
--
|
||||
2.16.3
|
||||
@@ -188,7 +188,7 @@ namespace epee
|
||||
void put_n(const std::uint8_t ch, const std::size_t count)
|
||||
{
|
||||
check(count);
|
||||
std::memset(tellp(), count, ch);
|
||||
std::memset(tellp(), ch, count);
|
||||
next_write_ += count;
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,6 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
buffer_ssl_init_fill = 0;
|
||||
if (is_income && m_ssl_support != epee::net_utils::ssl_support_t::e_ssl_support_disabled)
|
||||
socket().async_receive(boost::asio::buffer(buffer_),
|
||||
boost::asio::socket_base::message_peek,
|
||||
strand_.wrap(
|
||||
std::bind(&connection<t_protocol_handler>::handle_receive, self,
|
||||
std::placeholders::_1,
|
||||
@@ -270,8 +269,6 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
//_dbg3("[sock " << socket().native_handle() << "] add_ref, m_peer_number=" << mI->m_peer_number);
|
||||
CRITICAL_REGION_LOCAL(self->m_self_refs_lock);
|
||||
//_dbg3("[sock " << socket().native_handle() << "] add_ref 2, m_peer_number=" << mI->m_peer_number);
|
||||
if(m_was_shutdown)
|
||||
return false;
|
||||
++m_reference_count;
|
||||
m_self_ref = std::move(self);
|
||||
return true;
|
||||
@@ -334,6 +331,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
TRY_ENTRY();
|
||||
//_info("[sock " << socket().native_handle() << "] Async read calledback.");
|
||||
|
||||
if (m_was_shutdown)
|
||||
return;
|
||||
|
||||
if (!e)
|
||||
{
|
||||
double current_speed_down;
|
||||
@@ -360,6 +360,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
CRITICAL_REGION_LOCAL( epee::net_utils::network_throttle_manager::m_lock_get_global_throttle_in );
|
||||
delay = epee::net_utils::network_throttle_manager::get_global_throttle_in().get_sleep_time_after_tick( bytes_transferred );
|
||||
}
|
||||
|
||||
if (m_was_shutdown)
|
||||
return;
|
||||
|
||||
delay *= 0.5;
|
||||
long int ms = (long int)(delay * 100);
|
||||
@@ -431,6 +434,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
std::size_t bytes_transferred)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
if (m_was_shutdown) return;
|
||||
|
||||
if (e)
|
||||
{
|
||||
// offload the error case
|
||||
@@ -438,13 +444,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
return;
|
||||
}
|
||||
|
||||
reset_timer(get_timeout_from_bytes_read(bytes_transferred), false);
|
||||
|
||||
buffer_ssl_init_fill += bytes_transferred;
|
||||
if (buffer_ssl_init_fill <= get_ssl_magic_size())
|
||||
MTRACE("we now have " << buffer_ssl_init_fill << "/" << get_ssl_magic_size() << " bytes needed to detect SSL");
|
||||
if (buffer_ssl_init_fill < get_ssl_magic_size())
|
||||
{
|
||||
socket().async_receive(boost::asio::buffer(buffer_.data() + buffer_ssl_init_fill, buffer_.size() - buffer_ssl_init_fill),
|
||||
boost::asio::socket_base::message_peek,
|
||||
strand_.wrap(
|
||||
boost::bind(&connection<t_protocol_handler>::handle_receive, connection<t_protocol_handler>::shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
@@ -470,7 +474,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
if (m_ssl_support == epee::net_utils::ssl_support_t::e_ssl_support_enabled)
|
||||
{
|
||||
// Handshake
|
||||
if (!handshake(boost::asio::ssl::stream_base::server))
|
||||
if (!handshake(boost::asio::ssl::stream_base::server, boost::asio::const_buffer(buffer_.data(), buffer_ssl_init_fill)))
|
||||
{
|
||||
MERROR("SSL handshake failed");
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_want_close_connection, 1);
|
||||
@@ -485,6 +489,11 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
handle_read(e, buffer_ssl_init_fill);
|
||||
return;
|
||||
}
|
||||
|
||||
async_read_some(boost::asio::buffer(buffer_),
|
||||
strand_.wrap(
|
||||
@@ -651,6 +660,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds( ms ) );
|
||||
m_send_que_lock.lock();
|
||||
_dbg1("sleep for queue: " << ms);
|
||||
if (m_was_shutdown)
|
||||
return false;
|
||||
|
||||
if (retry > retry_limit) {
|
||||
MWARNING("send que size is more than ABSTRACT_SERVER_SEND_QUE_MAX_COUNT(" << ABSTRACT_SERVER_SEND_QUE_MAX_COUNT << "), shutting down connection");
|
||||
@@ -748,7 +759,8 @@ PRAGMA_WARNING_DISABLE_VS(4355)
|
||||
template<class t_protocol_handler>
|
||||
void connection<t_protocol_handler>::reset_timer(boost::posix_time::milliseconds ms, bool add)
|
||||
{
|
||||
if (ms.total_milliseconds() < 0)
|
||||
const auto tms = ms.total_milliseconds();
|
||||
if (tms < 0 || (add && tms == 0))
|
||||
{
|
||||
MWARNING("Ignoring negative timeout " << ms);
|
||||
return;
|
||||
|
||||
@@ -132,10 +132,10 @@ class connection_basic { // not-templated base class for rapid developmet of som
|
||||
ssl_support_t get_ssl_support() const { return m_ssl_support; }
|
||||
void disable_ssl() { m_ssl_support = epee::net_utils::ssl_support_t::e_ssl_support_disabled; }
|
||||
|
||||
bool handshake(boost::asio::ssl::stream_base::handshake_type type)
|
||||
bool handshake(boost::asio::ssl::stream_base::handshake_type type, boost::asio::const_buffer buffer = {})
|
||||
{
|
||||
//m_state != nullptr verified in constructor
|
||||
return m_state->ssl_options().handshake(socket_, type);
|
||||
return m_state->ssl_options().handshake(socket_, type, buffer);
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence, typename ReadHandler>
|
||||
|
||||
@@ -72,7 +72,8 @@ namespace levin
|
||||
|
||||
|
||||
#define LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED 0
|
||||
#define LEVIN_DEFAULT_MAX_PACKET_SIZE 100000000 //100MB by default
|
||||
#define LEVIN_INITIAL_MAX_PACKET_SIZE 256*1024 // 256 KiB before handshake
|
||||
#define LEVIN_DEFAULT_MAX_PACKET_SIZE 100000000 //100MB by default after handshake
|
||||
|
||||
#define LEVIN_PACKET_REQUEST 0x00000001
|
||||
#define LEVIN_PACKET_RESPONSE 0x00000002
|
||||
|
||||
@@ -84,7 +84,8 @@ class async_protocol_handler_config
|
||||
|
||||
public:
|
||||
typedef t_connection_context connection_context;
|
||||
uint64_t m_max_packet_size;
|
||||
uint64_t m_initial_max_packet_size;
|
||||
uint64_t m_max_packet_size;
|
||||
uint64_t m_invoke_timeout;
|
||||
|
||||
int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, boost::uuids::uuid connection_id);
|
||||
@@ -105,7 +106,7 @@ public:
|
||||
size_t get_in_connections_count();
|
||||
void set_handler(levin_commands_handler<t_connection_context>* handler, void (*destroy)(levin_commands_handler<t_connection_context>*) = NULL);
|
||||
|
||||
async_protocol_handler_config():m_pcommands_handler(NULL), m_pcommands_handler_destroy(NULL), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE), m_invoke_timeout(LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
|
||||
async_protocol_handler_config():m_pcommands_handler(NULL), m_pcommands_handler_destroy(NULL), m_initial_max_packet_size(LEVIN_INITIAL_MAX_PACKET_SIZE), m_max_packet_size(LEVIN_DEFAULT_MAX_PACKET_SIZE), m_invoke_timeout(LEVIN_DEFAULT_TIMEOUT_PRECONFIGURED)
|
||||
{}
|
||||
~async_protocol_handler_config() { set_handler(NULL, NULL); }
|
||||
void del_out_connections(size_t count);
|
||||
@@ -162,6 +163,7 @@ public:
|
||||
net_utils::i_service_endpoint* m_pservice_endpoint;
|
||||
config_type& m_config;
|
||||
t_connection_context& m_connection_context;
|
||||
std::atomic<uint64_t> m_max_packet_size;
|
||||
|
||||
net_utils::buffer m_cache_in_buffer;
|
||||
stream_state m_state;
|
||||
@@ -289,7 +291,8 @@ public:
|
||||
m_current_head(bucket_head2()),
|
||||
m_pservice_endpoint(psnd_hndlr),
|
||||
m_config(config),
|
||||
m_connection_context(conn_context),
|
||||
m_connection_context(conn_context),
|
||||
m_max_packet_size(config.m_initial_max_packet_size),
|
||||
m_cache_in_buffer(4 * 1024),
|
||||
m_state(stream_state_head)
|
||||
{
|
||||
@@ -399,13 +402,14 @@ public:
|
||||
}
|
||||
|
||||
// these should never fail, but do runtime check for safety
|
||||
CHECK_AND_ASSERT_MES(m_config.m_max_packet_size >= m_cache_in_buffer.size(), false, "Bad m_cache_in_buffer.size()");
|
||||
CHECK_AND_ASSERT_MES(m_config.m_max_packet_size - m_cache_in_buffer.size() >= m_fragment_buffer.size(), false, "Bad m_cache_in_buffer.size() + m_fragment_buffer.size()");
|
||||
const uint64_t max_packet_size = m_max_packet_size;
|
||||
CHECK_AND_ASSERT_MES(max_packet_size >= m_cache_in_buffer.size(), false, "Bad m_cache_in_buffer.size()");
|
||||
CHECK_AND_ASSERT_MES(max_packet_size - m_cache_in_buffer.size() >= m_fragment_buffer.size(), false, "Bad m_cache_in_buffer.size() + m_fragment_buffer.size()");
|
||||
|
||||
// flipped to subtraction; prevent overflow since m_max_packet_size is variable and public
|
||||
if(cb > m_config.m_max_packet_size - m_cache_in_buffer.size() - m_fragment_buffer.size())
|
||||
if(cb > max_packet_size - m_cache_in_buffer.size() - m_fragment_buffer.size())
|
||||
{
|
||||
MWARNING(m_connection_context << "Maximum packet size exceed!, m_max_packet_size = " << m_config.m_max_packet_size
|
||||
MWARNING(m_connection_context << "Maximum packet size exceed!, m_max_packet_size = " << max_packet_size
|
||||
<< ", packet received " << m_cache_in_buffer.size() + cb
|
||||
<< ", connection will be closed.");
|
||||
return false;
|
||||
@@ -430,7 +434,7 @@ public:
|
||||
//async call scenario
|
||||
boost::shared_ptr<invoke_response_handler_base> response_handler = m_invoke_response_handlers.front();
|
||||
response_handler->reset_timer();
|
||||
MDEBUG(m_connection_context << "LEVIN_PACKET partial msg received. len=" << cb);
|
||||
MDEBUG(m_connection_context << "LEVIN_PACKET partial msg received. len=" << cb << ", current total " << m_cache_in_buffer.size() << "/" << m_current_head.m_cb << " (" << (100.0f * m_cache_in_buffer.size() / (m_current_head.m_cb ? m_current_head.m_cb : 1)) << "%)");
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -465,6 +469,14 @@ public:
|
||||
temp = std::move(m_fragment_buffer);
|
||||
m_fragment_buffer.clear();
|
||||
std::memcpy(std::addressof(m_current_head), std::addressof(temp[0]), sizeof(bucket_head2));
|
||||
const size_t max_bytes = m_connection_context.get_max_bytes(m_current_head.m_command);
|
||||
if(m_current_head.m_cb > std::min<size_t>(max_packet_size, max_bytes))
|
||||
{
|
||||
MERROR(m_connection_context << "Maximum packet size exceed!, m_max_packet_size = " << std::min<size_t>(max_packet_size, max_bytes)
|
||||
<< ", packet header received " << m_current_head.m_cb << ", command " << m_current_head.m_command
|
||||
<< ", connection will be closed.");
|
||||
return false;
|
||||
}
|
||||
buff_to_invoke = {reinterpret_cast<const uint8_t*>(temp.data()) + sizeof(bucket_head2), temp.size() - sizeof(bucket_head2)};
|
||||
}
|
||||
|
||||
@@ -519,6 +531,10 @@ public:
|
||||
m_current_head.m_command, buff_to_invoke, return_buff, m_connection_context
|
||||
);
|
||||
|
||||
// peer_id remains unset if dropped
|
||||
if (m_current_head.m_command == m_connection_context.handshake_command() && m_connection_context.handshake_complete())
|
||||
m_max_packet_size = m_config.m_max_packet_size;
|
||||
|
||||
bucket_head2 head = make_header(m_current_head.m_command, return_buff.size(), LEVIN_PACKET_RESPONSE, false);
|
||||
head.m_return_code = SWAP32LE(return_code);
|
||||
return_buff.insert(0, reinterpret_cast<const char*>(&head), sizeof(head));
|
||||
@@ -577,10 +593,11 @@ public:
|
||||
m_cache_in_buffer.erase(sizeof(bucket_head2));
|
||||
m_state = stream_state_body;
|
||||
m_oponent_protocol_ver = m_current_head.m_protocol_version;
|
||||
if(m_current_head.m_cb > m_config.m_max_packet_size)
|
||||
const size_t max_bytes = m_connection_context.get_max_bytes(m_current_head.m_command);
|
||||
if(m_current_head.m_cb > std::min<size_t>(max_packet_size, max_bytes))
|
||||
{
|
||||
LOG_ERROR_CC(m_connection_context, "Maximum packet size exceed!, m_max_packet_size = " << m_config.m_max_packet_size
|
||||
<< ", packet header received " << m_current_head.m_cb
|
||||
LOG_ERROR_CC(m_connection_context, "Maximum packet size exceed!, m_max_packet_size = " << std::min<size_t>(max_packet_size, max_bytes)
|
||||
<< ", packet header received " << m_current_head.m_cb << ", command " << m_current_head.m_command
|
||||
<< ", connection will be closed.");
|
||||
return false;
|
||||
}
|
||||
@@ -634,6 +651,9 @@ public:
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 0);
|
||||
CRITICAL_REGION_BEGIN(m_invoke_response_handlers_lock);
|
||||
|
||||
if (command == m_connection_context.handshake_command())
|
||||
m_max_packet_size = m_config.m_max_packet_size;
|
||||
|
||||
if(!send_message(command, in_buff, LEVIN_PACKET_REQUEST, true))
|
||||
{
|
||||
LOG_ERROR_CC(m_connection_context, "Failed to do_send");
|
||||
@@ -675,6 +695,9 @@ public:
|
||||
|
||||
boost::interprocess::ipcdetail::atomic_write32(&m_invoke_buf_ready, 0);
|
||||
|
||||
if (command == m_connection_context.handshake_command())
|
||||
m_max_packet_size = m_config.m_max_packet_size;
|
||||
|
||||
if (!send_message(command, in_buff, LEVIN_PACKET_REQUEST, true))
|
||||
{
|
||||
LOG_ERROR_CC(m_connection_context, "Failed to send request");
|
||||
@@ -777,36 +800,32 @@ void async_protocol_handler_config<t_connection_context>::del_connection(async_p
|
||||
template<class t_connection_context>
|
||||
void async_protocol_handler_config<t_connection_context>::delete_connections(size_t count, bool incoming)
|
||||
{
|
||||
std::vector <boost::uuids::uuid> connections;
|
||||
std::vector<typename connections_map::mapped_type> connections;
|
||||
|
||||
auto scope_exit_handler = misc_utils::create_scope_leave_handler([&connections]{
|
||||
for (auto &aph: connections)
|
||||
aph->finish_outer_call();
|
||||
});
|
||||
|
||||
CRITICAL_REGION_BEGIN(m_connects_lock);
|
||||
for (auto& c: m_connects)
|
||||
{
|
||||
if (c.second->m_connection_context.m_is_income == incoming)
|
||||
connections.push_back(c.first);
|
||||
if (c.second->start_outer_call())
|
||||
connections.push_back(c.second);
|
||||
}
|
||||
|
||||
// close random connections from the provided set
|
||||
// TODO or better just keep removing random elements (performance)
|
||||
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||
shuffle(connections.begin(), connections.end(), std::default_random_engine(seed));
|
||||
while (count > 0 && connections.size() > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
auto i = connections.end() - 1;
|
||||
async_protocol_handler<t_connection_context> *conn = m_connects.at(*i);
|
||||
del_connection(conn);
|
||||
conn->close();
|
||||
connections.erase(i);
|
||||
}
|
||||
catch (const std::out_of_range &e)
|
||||
{
|
||||
MWARNING("Connection not found in m_connects, continuing");
|
||||
}
|
||||
--count;
|
||||
}
|
||||
for (size_t i = 0; i < connections.size() && i < count; ++i)
|
||||
m_connects.erase(connections[i]->get_connection_id());
|
||||
|
||||
CRITICAL_REGION_END();
|
||||
|
||||
for (size_t i = 0; i < connections.size() && i < count; ++i)
|
||||
connections[i]->close();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
@@ -868,23 +887,35 @@ int async_protocol_handler_config<t_connection_context>::invoke_async(int comman
|
||||
template<class t_connection_context> template<class callback_t>
|
||||
bool async_protocol_handler_config<t_connection_context>::foreach_connection(const callback_t &cb)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_connects_lock);
|
||||
for(auto& c: m_connects)
|
||||
{
|
||||
async_protocol_handler<t_connection_context>* aph = c.second;
|
||||
if(!cb(aph->get_context_ref()))
|
||||
std::vector<typename connections_map::mapped_type> conn;
|
||||
|
||||
auto scope_exit_handler = misc_utils::create_scope_leave_handler([&conn]{
|
||||
for (auto &aph: conn)
|
||||
aph->finish_outer_call();
|
||||
});
|
||||
|
||||
CRITICAL_REGION_BEGIN(m_connects_lock);
|
||||
conn.reserve(m_connects.size());
|
||||
for (auto &e: m_connects)
|
||||
if (e.second->start_outer_call())
|
||||
conn.push_back(e.second);
|
||||
CRITICAL_REGION_END()
|
||||
|
||||
for (auto &aph: conn)
|
||||
if (!cb(aph->get_context_ref()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context> template<class callback_t>
|
||||
bool async_protocol_handler_config<t_connection_context>::for_connection(const boost::uuids::uuid &connection_id, const callback_t &cb)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_connects_lock);
|
||||
async_protocol_handler<t_connection_context>* aph = find_connection(connection_id);
|
||||
if (!aph)
|
||||
async_protocol_handler<t_connection_context>* aph = nullptr;
|
||||
if (find_and_lock_connection(connection_id, aph) != LEVIN_OK)
|
||||
return false;
|
||||
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
|
||||
boost::bind(&async_protocol_handler<t_connection_context>::finish_outer_call, aph));
|
||||
if(!cb(aph->get_context_ref()))
|
||||
return false;
|
||||
return true;
|
||||
@@ -947,12 +978,14 @@ int async_protocol_handler_config<t_connection_context>::send(byte_slice message
|
||||
template<class t_connection_context>
|
||||
bool async_protocol_handler_config<t_connection_context>::close(boost::uuids::uuid connection_id)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_connects_lock);
|
||||
async_protocol_handler<t_connection_context>* aph = find_connection(connection_id);
|
||||
if (!aph)
|
||||
async_protocol_handler<t_connection_context>* aph = nullptr;
|
||||
if (find_and_lock_connection(connection_id, aph) != LEVIN_OK)
|
||||
return false;
|
||||
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
|
||||
boost::bind(&async_protocol_handler<t_connection_context>::finish_outer_call, aph));
|
||||
if (!aph->close())
|
||||
return false;
|
||||
CRITICAL_REGION_LOCAL(m_connects_lock);
|
||||
m_connects.erase(connection_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ namespace net_utils
|
||||
// SSL Options
|
||||
if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
if (!m_ssl_options.handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, addr, timeout))
|
||||
if (!m_ssl_options.handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, {}, addr, timeout))
|
||||
{
|
||||
if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
|
||||
@@ -132,6 +132,7 @@ namespace net_utils
|
||||
bool handshake(
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket,
|
||||
boost::asio::ssl::stream_base::handshake_type type,
|
||||
boost::asio::const_buffer buffer = {},
|
||||
const std::string& host = {},
|
||||
std::chrono::milliseconds timeout = std::chrono::seconds(15)) const;
|
||||
};
|
||||
|
||||
@@ -141,7 +141,6 @@ public:
|
||||
|
||||
rolling_median_t(rolling_median_t &&m)
|
||||
{
|
||||
free(data);
|
||||
memcpy(this, &m, sizeof(rolling_median_t));
|
||||
m.data = NULL;
|
||||
}
|
||||
|
||||
@@ -97,7 +97,12 @@ namespace epee
|
||||
return false;
|
||||
}
|
||||
|
||||
return serialization::load_t_from_binary(result_struct, epee::strspan<uint8_t>(pri->m_body));
|
||||
static const constexpr epee::serialization::portable_storage::limits_t default_http_bin_limits = {
|
||||
65536 * 3, // objects
|
||||
65536 * 3, // fields
|
||||
65536 * 3, // strings
|
||||
};
|
||||
return serialization::load_t_from_binary(result_struct, epee::strspan<uint8_t>(pri->m_body), &default_http_bin_limits);
|
||||
}
|
||||
|
||||
template<class t_request, class t_response, class t_transport>
|
||||
|
||||
@@ -50,6 +50,11 @@ namespace
|
||||
snprintf(buf, sizeof(buf), "command-%u", command);
|
||||
return on_levin_traffic(context, initiator, sent, error, bytes, buf);
|
||||
}
|
||||
static const constexpr epee::serialization::portable_storage::limits_t default_levin_limits = {
|
||||
8192, // objects
|
||||
16384, // fields
|
||||
16384, // strings
|
||||
};
|
||||
}
|
||||
|
||||
namespace epee
|
||||
@@ -75,7 +80,7 @@ namespace epee
|
||||
return false;
|
||||
}
|
||||
serialization::portable_storage stg_ret;
|
||||
if(!stg_ret.load_from_binary(buff_to_recv))
|
||||
if(!stg_ret.load_from_binary(buff_to_recv, &default_levin_limits))
|
||||
{
|
||||
LOG_ERROR("Failed to load_from_binary on command " << command);
|
||||
return false;
|
||||
@@ -121,7 +126,7 @@ namespace epee
|
||||
return false;
|
||||
}
|
||||
typename serialization::portable_storage stg_ret;
|
||||
if(!stg_ret.load_from_binary(buff_to_recv))
|
||||
if(!stg_ret.load_from_binary(buff_to_recv, &default_levin_limits))
|
||||
{
|
||||
on_levin_traffic(context, true, false, true, buff_to_recv.size(), command);
|
||||
LOG_ERROR("Failed to load_from_binary on command " << command);
|
||||
@@ -152,7 +157,7 @@ namespace epee
|
||||
return false;
|
||||
}
|
||||
serialization::portable_storage stg_ret;
|
||||
if(!stg_ret.load_from_binary(buff))
|
||||
if(!stg_ret.load_from_binary(buff, &default_levin_limits))
|
||||
{
|
||||
on_levin_traffic(context, true, false, true, buff.size(), command);
|
||||
LOG_ERROR("Failed to load_from_binary on command " << command);
|
||||
@@ -202,7 +207,7 @@ namespace epee
|
||||
int buff_to_t_adapter(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, callback_t cb, t_context& context )
|
||||
{
|
||||
serialization::portable_storage strg;
|
||||
if(!strg.load_from_binary(in_buff))
|
||||
if(!strg.load_from_binary(in_buff, &default_levin_limits))
|
||||
{
|
||||
on_levin_traffic(context, false, false, true, in_buff.size(), command);
|
||||
LOG_ERROR("Failed to load_from_binary in command " << command);
|
||||
@@ -236,7 +241,7 @@ namespace epee
|
||||
int buff_to_t_adapter(t_owner* powner, int command, const epee::span<const uint8_t> in_buff, callback_t cb, t_context& context)
|
||||
{
|
||||
serialization::portable_storage strg;
|
||||
if(!strg.load_from_binary(in_buff))
|
||||
if(!strg.load_from_binary(in_buff, &default_levin_limits))
|
||||
{
|
||||
on_levin_traffic(context, false, false, true, in_buff.size(), command);
|
||||
LOG_ERROR("Failed to load_from_binary in notify " << command);
|
||||
|
||||
@@ -54,6 +54,13 @@ namespace epee
|
||||
typedef epee::serialization::harray harray;
|
||||
typedef storage_entry meta_entry;
|
||||
|
||||
struct limits_t
|
||||
{
|
||||
size_t n_objects;
|
||||
size_t n_fields;
|
||||
size_t n_strings; // not counting field names
|
||||
};
|
||||
|
||||
portable_storage(){}
|
||||
virtual ~portable_storage(){}
|
||||
hsection open_section(const std::string& section_name, hsection hparent_section, bool create_if_notexist = false);
|
||||
@@ -84,8 +91,8 @@ namespace epee
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
bool store_to_binary(binarybuffer& target);
|
||||
bool load_from_binary(const epee::span<const uint8_t> target);
|
||||
bool load_from_binary(const std::string& target) { return load_from_binary(epee::strspan<uint8_t>(target)); }
|
||||
bool load_from_binary(const epee::span<const uint8_t> target, const limits_t *limits = NULL);
|
||||
bool load_from_binary(const std::string& target, const limits_t *limits = NULL) { return load_from_binary(epee::strspan<uint8_t>(target), limits); }
|
||||
template<class trace_policy>
|
||||
bool dump_as_xml(std::string& targetObj, const std::string& root_name = "");
|
||||
bool dump_as_json(std::string& targetObj, size_t indent = 0, bool insert_newlines = true);
|
||||
@@ -150,7 +157,7 @@ namespace epee
|
||||
CATCH_ENTRY("portable_storage::store_to_binary", false)
|
||||
}
|
||||
inline
|
||||
bool portable_storage::load_from_binary(const epee::span<const uint8_t> source)
|
||||
bool portable_storage::load_from_binary(const epee::span<const uint8_t> source, const limits_t *limits)
|
||||
{
|
||||
m_root.m_entries.clear();
|
||||
if(source.size() < sizeof(storage_block_header))
|
||||
@@ -173,6 +180,8 @@ namespace epee
|
||||
}
|
||||
TRY_ENTRY();
|
||||
throwable_buffer_reader buf_reader(source.data()+sizeof(storage_block_header), source.size()-sizeof(storage_block_header));
|
||||
if (limits)
|
||||
buf_reader.set_limits(limits->n_objects, limits->n_fields, limits->n_strings);
|
||||
buf_reader.read(m_root);
|
||||
return true;//TODO:
|
||||
CATCH_ENTRY("portable_storage::load_from_binary", false);
|
||||
@@ -282,6 +291,7 @@ namespace epee
|
||||
static_assert(std::is_rvalue_reference<entry_type&&>(), "unexpected copy of value");
|
||||
TRY_ENTRY();
|
||||
CHECK_AND_ASSERT(psection, nullptr);
|
||||
CHECK_AND_ASSERT(!pentry_name.empty(), nullptr);
|
||||
auto ins_res = psection->m_entries.emplace(pentry_name, std::forward<entry_type>(entry));
|
||||
return &ins_res.first->second;
|
||||
CATCH_ENTRY("portable_storage::insert_new_entry_get_storage_entry", nullptr);
|
||||
|
||||
@@ -42,6 +42,24 @@ namespace epee
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template<typename T>
|
||||
struct ps_min_bytes {
|
||||
static constexpr const size_t strict = 4096; // actual low bound
|
||||
};
|
||||
template<> struct ps_min_bytes<uint64_t> { static constexpr const size_t strict = 8; };
|
||||
template<> struct ps_min_bytes<int64_t> { static constexpr const size_t strict = 8; };
|
||||
template<> struct ps_min_bytes<uint32_t> { static constexpr const size_t strict = 4; };
|
||||
template<> struct ps_min_bytes<int32_t> { static constexpr const size_t strict = 4; };
|
||||
template<> struct ps_min_bytes<uint16_t> { static constexpr const size_t strict = 2; };
|
||||
template<> struct ps_min_bytes<int16_t> { static constexpr const size_t strict = 2; };
|
||||
template<> struct ps_min_bytes<uint8_t> { static constexpr const size_t strict = 1; };
|
||||
template<> struct ps_min_bytes<int8_t> { static constexpr const size_t strict = 1; };
|
||||
template<> struct ps_min_bytes<double> { static constexpr const size_t strict = 8; };
|
||||
template<> struct ps_min_bytes<bool> { static constexpr const size_t strict = 1; };
|
||||
template<> struct ps_min_bytes<std::string> { static constexpr const size_t strict = 2; };
|
||||
template<> struct ps_min_bytes<section> { static constexpr const size_t strict = 1; };
|
||||
template<> struct ps_min_bytes<array_entry> { static constexpr const size_t strict = 1; };
|
||||
|
||||
struct throwable_buffer_reader
|
||||
{
|
||||
throwable_buffer_reader(const void* ptr, size_t sz);
|
||||
@@ -61,6 +79,9 @@ namespace epee
|
||||
void read(section& sec);
|
||||
void read(std::string& str);
|
||||
void read(array_entry &ae);
|
||||
template<class t_type>
|
||||
size_t min_bytes() const;
|
||||
void set_limits(size_t objects, size_t fields, size_t strings);
|
||||
private:
|
||||
struct recursuion_limitation_guard
|
||||
{
|
||||
@@ -81,6 +102,13 @@ namespace epee
|
||||
const uint8_t* m_ptr;
|
||||
size_t m_count;
|
||||
size_t m_recursion_count;
|
||||
size_t m_objects;
|
||||
size_t m_fields;
|
||||
size_t m_strings;
|
||||
|
||||
size_t max_objects;
|
||||
size_t max_fields;
|
||||
size_t max_strings;
|
||||
};
|
||||
|
||||
inline throwable_buffer_reader::throwable_buffer_reader(const void* ptr, size_t sz)
|
||||
@@ -92,6 +120,12 @@ namespace epee
|
||||
m_ptr = (uint8_t*)ptr;
|
||||
m_count = sz;
|
||||
m_recursion_count = 0;
|
||||
m_objects = 0;
|
||||
m_fields = 0;
|
||||
m_strings = 0;
|
||||
max_objects = std::numeric_limits<size_t>::max();
|
||||
max_fields = std::numeric_limits<size_t>::max();
|
||||
max_strings = std::numeric_limits<size_t>::max();
|
||||
}
|
||||
inline
|
||||
void throwable_buffer_reader::read(void* target, size_t count)
|
||||
@@ -108,6 +142,7 @@ namespace epee
|
||||
RECURSION_LIMITATION();
|
||||
uint8_t name_len = 0;
|
||||
read(name_len);
|
||||
CHECK_AND_ASSERT_THROW_MES(name_len > 0, "Section name is missing");
|
||||
sce_name.resize(name_len);
|
||||
read((void*)sce_name.data(), name_len);
|
||||
}
|
||||
@@ -138,7 +173,18 @@ namespace epee
|
||||
//for pod types
|
||||
array_entry_t<type_name> sa;
|
||||
size_t size = read_varint();
|
||||
CHECK_AND_ASSERT_THROW_MES(size <= m_count, "Size sanity check failed");
|
||||
CHECK_AND_ASSERT_THROW_MES(size <= m_count / ps_min_bytes<type_name>::strict, "Size sanity check failed");
|
||||
if (std::is_same<type_name, section>())
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(size <= max_objects - m_objects, "Too many objects");
|
||||
m_objects += size;
|
||||
}
|
||||
else if (std::is_same<type_name, std::string>())
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(size <= max_strings - m_strings, "Too many strings");
|
||||
m_strings += size;
|
||||
}
|
||||
|
||||
sa.reserve(size);
|
||||
//TODO: add some optimization here later
|
||||
while(size--)
|
||||
@@ -204,6 +250,8 @@ namespace epee
|
||||
inline storage_entry throwable_buffer_reader::read_se<std::string>()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
CHECK_AND_ASSERT_THROW_MES(m_strings + 1 <= max_strings, "Too many strings");
|
||||
m_strings += 1;
|
||||
return storage_entry(read<std::string>());
|
||||
}
|
||||
|
||||
@@ -212,6 +260,8 @@ namespace epee
|
||||
inline storage_entry throwable_buffer_reader::read_se<section>()
|
||||
{
|
||||
RECURSION_LIMITATION();
|
||||
CHECK_AND_ASSERT_THROW_MES(m_objects < max_objects, "Too many objects");
|
||||
++m_objects;
|
||||
section s;//use extra variable due to vs bug, line "storage_entry se(section()); " can't be compiled in visual studio
|
||||
storage_entry se(std::move(s));
|
||||
section& section_entry = boost::get<section>(se);
|
||||
@@ -263,12 +313,16 @@ namespace epee
|
||||
RECURSION_LIMITATION();
|
||||
sec.m_entries.clear();
|
||||
size_t count = read_varint();
|
||||
CHECK_AND_ASSERT_THROW_MES(count <= max_fields - m_fields, "Too many object fields");
|
||||
m_fields += count;
|
||||
while(count--)
|
||||
{
|
||||
//read section name string
|
||||
std::string sec_name;
|
||||
read_sec_name(sec_name);
|
||||
sec.m_entries.emplace(std::move(sec_name), load_storage_entry());
|
||||
const auto insert_loc = sec.m_entries.lower_bound(sec_name);
|
||||
CHECK_AND_ASSERT_THROW_MES(insert_loc == sec.m_entries.end() || insert_loc->first != sec_name, "duplicate key: " << sec_name);
|
||||
sec.m_entries.emplace_hint(insert_loc, std::move(sec_name), load_storage_entry());
|
||||
}
|
||||
}
|
||||
inline
|
||||
@@ -289,5 +343,12 @@ namespace epee
|
||||
RECURSION_LIMITATION();
|
||||
CHECK_AND_ASSERT_THROW_MES(false, "Reading array entry is not supported");
|
||||
}
|
||||
inline
|
||||
void throwable_buffer_reader::set_limits(size_t objects, size_t fields, size_t strings)
|
||||
{
|
||||
max_objects = objects;
|
||||
max_fields = fields;
|
||||
max_strings = strings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,10 +84,10 @@ namespace epee
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
template<class t_struct>
|
||||
bool load_t_from_binary(t_struct& out, const epee::span<const uint8_t> binary_buff)
|
||||
bool load_t_from_binary(t_struct& out, const epee::span<const uint8_t> binary_buff, const epee::serialization::portable_storage::limits_t *limits = NULL)
|
||||
{
|
||||
portable_storage ps;
|
||||
bool rs = ps.load_from_binary(binary_buff);
|
||||
bool rs = ps.load_from_binary(binary_buff, limits);
|
||||
if(!rs)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -211,6 +211,7 @@ namespace epee
|
||||
for(const section_pair& se: sec.m_entries)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(se.first.size() < std::numeric_limits<uint8_t>::max(), "storage_entry_name is too long: " << se.first.size() << ", val: " << se.first);
|
||||
CHECK_AND_ASSERT_THROW_MES(!se.first.empty(), "storage_entry_name is empty");
|
||||
uint8_t len = static_cast<uint8_t>(se.first.size());
|
||||
strm.write((const char*)&len, sizeof(len));
|
||||
strm.write(se.first.data(), size_t(len));
|
||||
|
||||
@@ -473,6 +473,7 @@ bool ssl_options_t::has_fingerprint(boost::asio::ssl::verify_context &ctx) const
|
||||
bool ssl_options_t::handshake(
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket,
|
||||
boost::asio::ssl::stream_base::handshake_type type,
|
||||
boost::asio::const_buffer buffer,
|
||||
const std::string& host,
|
||||
std::chrono::milliseconds timeout) const
|
||||
{
|
||||
@@ -530,7 +531,7 @@ bool ssl_options_t::handshake(
|
||||
});
|
||||
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
socket.async_handshake(type, boost::lambda::var(ec) = boost::lambda::_1);
|
||||
socket.async_handshake(type, boost::asio::buffer(buffer), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
if (io_service.stopped())
|
||||
{
|
||||
io_service.reset();
|
||||
|
||||
@@ -126,7 +126,7 @@ Setup for LXC:
|
||||
|
||||
```bash
|
||||
GH_USER=fluffypony
|
||||
VERSION=v0.17.1.7
|
||||
VERSION=v0.17.2.0
|
||||
|
||||
./gitian-build.py --setup $GH_USER $VERSION
|
||||
```
|
||||
@@ -182,7 +182,7 @@ If you chose to do detached signing using `--detach-sign` above (recommended), y
|
||||
|
||||
```bash
|
||||
GH_USER=fluffypony
|
||||
VERSION=v0.17.1.7
|
||||
VERSION=v0.17.2.0
|
||||
|
||||
gpg --detach-sign ${VERSION}-linux/${GH_USER}/monero-linux-*-build.assert
|
||||
gpg --detach-sign ${VERSION}-win/${GH_USER}/monero-win-*-build.assert
|
||||
|
||||
Vendored
+2
-2
@@ -3461,9 +3461,9 @@ mdb_freelist_save(MDB_txn *txn)
|
||||
} else {
|
||||
x = mdb_mid2l_search(dl, mp->mp_pgno);
|
||||
mdb_tassert(txn, dl[x].mid == mp->mp_pgno);
|
||||
mdb_dpage_free(env, mp);
|
||||
}
|
||||
dl[x].mptr = NULL;
|
||||
mdb_dpage_free(env, mp);
|
||||
}
|
||||
{
|
||||
/* squash freed slots out of the dirty list */
|
||||
@@ -7867,7 +7867,7 @@ put_sub:
|
||||
xdata.mv_size = 0;
|
||||
xdata.mv_data = "";
|
||||
leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
|
||||
if (flags == MDB_CURRENT) {
|
||||
if ((flags & (MDB_CURRENT|MDB_APPENDDUP)) == MDB_CURRENT) {
|
||||
xflags = MDB_CURRENT|MDB_NOSPILL;
|
||||
} else {
|
||||
mdb_xcursor_init1(mc, leaf);
|
||||
|
||||
@@ -1312,17 +1312,20 @@ public:
|
||||
* height. The number of blocks returned is variable, based on the max_size passed.
|
||||
*
|
||||
* @param start_height the height of the first block
|
||||
* @param min_count the minimum number of blocks to return, if they exist
|
||||
* @param max_count the maximum number of blocks to return
|
||||
* @param min_block_count the minimum number of blocks to return, if they exist
|
||||
* @param max_block_count the maximum number of blocks to return
|
||||
* @param max_tx_count the maximum number of txes to return
|
||||
* @param max_size the maximum size of block/transaction data to return (will be exceeded by one blocks's worth at most, if min_count is met)
|
||||
* @param blocks the returned block/transaction data
|
||||
* @param pruned whether to return full or pruned tx data
|
||||
* @param skip_coinbase whether to return or skip coinbase transactions (they're in blocks regardless)
|
||||
* @param get_miner_tx_hash whether to calculate and return the miner (coinbase) tx hash
|
||||
*
|
||||
* The call will return at least min_block_count if possible, even if this contravenes max_tx_count
|
||||
*
|
||||
* @return true iff the blocks and transactions were found
|
||||
*/
|
||||
virtual bool get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const = 0;
|
||||
virtual bool get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const = 0;
|
||||
|
||||
/**
|
||||
* @brief fetches the prunable transaction blob with the given hash
|
||||
|
||||
@@ -3171,7 +3171,7 @@ bool BlockchainLMDB::get_pruned_tx_blobs_from(const crypto::hash& h, size_t coun
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const
|
||||
bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
@@ -3185,14 +3185,15 @@ bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_count, si
|
||||
RCURSOR(txs_prunable);
|
||||
}
|
||||
|
||||
blocks.reserve(std::min<size_t>(max_count, 10000)); // guard against very large max count if only checking bytes
|
||||
blocks.reserve(std::min<size_t>(max_block_count, 10000)); // guard against very large max count if only checking bytes
|
||||
const uint64_t blockchain_height = height();
|
||||
uint64_t size = 0;
|
||||
size_t num_txes = 0;
|
||||
MDB_val_copy<uint64_t> key(start_height);
|
||||
MDB_val k, v, val_tx_id;
|
||||
uint64_t tx_id = ~0;
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
for (uint64_t h = start_height; h < blockchain_height && blocks.size() < max_count && (size < max_size || blocks.size() < min_count); ++h)
|
||||
for (uint64_t h = start_height; h < blockchain_height && blocks.size() < max_block_count && (size < max_size || blocks.size() < min_block_count); ++h)
|
||||
{
|
||||
MDB_cursor_op op = h == start_height ? MDB_SET : MDB_NEXT;
|
||||
int result = mdb_cursor_get(m_cur_blocks, &key, &v, op);
|
||||
@@ -3243,6 +3244,7 @@ bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_count, si
|
||||
op = MDB_NEXT;
|
||||
|
||||
current_block.second.reserve(b.tx_hashes.size());
|
||||
num_txes += b.tx_hashes.size() + (skip_coinbase ? 0 : 1);
|
||||
for (const auto &tx_hash: b.tx_hashes)
|
||||
{
|
||||
// get pruned data
|
||||
@@ -3262,6 +3264,9 @@ bool BlockchainLMDB::get_blocks_from(uint64_t start_height, size_t min_count, si
|
||||
current_block.second.push_back(std::make_pair(tx_hash, std::move(tx_blob)));
|
||||
size += current_block.second.back().second.size();
|
||||
}
|
||||
|
||||
if (blocks.size() >= min_block_count && num_txes >= max_tx_count)
|
||||
break;
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
@@ -257,7 +257,7 @@ public:
|
||||
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
|
||||
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
|
||||
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const;
|
||||
virtual bool get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const;
|
||||
virtual bool get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const;
|
||||
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const;
|
||||
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const;
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
|
||||
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
|
||||
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const override { return false; }
|
||||
virtual bool get_blocks_from(uint64_t start_height, size_t min_count, size_t max_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const override { return false; }
|
||||
virtual bool get_blocks_from(uint64_t start_height, size_t min_block_count, size_t max_block_count, size_t max_tx_count, size_t max_size, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata>>>>& blocks, bool pruned, bool skip_coinbase, bool get_miner_tx_hash) const override { return false; }
|
||||
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
|
||||
virtual bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const override { return false; }
|
||||
virtual uint64_t get_block_height(const crypto::hash& h) const override { return 0; }
|
||||
|
||||
Binary file not shown.
@@ -244,6 +244,9 @@ namespace cryptonote
|
||||
ADD_CHECKPOINT2(2235500, "3eac1a1253495733e10d00fd5e8e1639741566d91bae38bc6d3342af6b75da53", "0x10cea232ce71d23");
|
||||
ADD_CHECKPOINT2(2244000, "f06b8a19a75070cd002414d9d3ce59cf6b11ed9db464c6b84d3f22abbff84fae", "0x112b3331539f585");
|
||||
ADD_CHECKPOINT2(2248500, "125d0872f00b54730b1e6f925f9d211b0158dd0e254de8cefa371f2e7aba5118", "0x115c89ab7abec4a");
|
||||
ADD_CHECKPOINT2(2257500, "99643c32f27b157c6952a67af7dbe07ca819e71df386fa9379a344686d2950cf", "0x11c2f448d4f8830");
|
||||
ADD_CHECKPOINT2(2265000, "727a6228a71f5b35c899553ee19d60bfc10c126a009ffd633afb30666e8edbe6", "0x121a33e656ecad4");
|
||||
ADD_CHECKPOINT2(2325000, "f61261994b368700f0cbbfb4477433fa36a3c7537908ab2d1a06ac2987cc8b01", "0x154bceeffaff847");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -871,10 +871,19 @@ std::string get_nix_version_display_string()
|
||||
return max_concurrency;
|
||||
}
|
||||
|
||||
bool is_privacy_preserving_network(const std::string &address)
|
||||
{
|
||||
if (boost::ends_with(address, ".onion"))
|
||||
return true;
|
||||
if (boost::ends_with(address, ".i2p"))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_local_address(const std::string &address)
|
||||
{
|
||||
// always assume Tor/I2P addresses to be untrusted by default
|
||||
if (boost::ends_with(address, ".onion") || boost::ends_with(address, ".i2p"))
|
||||
if (is_privacy_preserving_network(address))
|
||||
{
|
||||
MDEBUG("Address '" << address << "' is Tor/I2P, non local");
|
||||
return false;
|
||||
|
||||
@@ -228,6 +228,7 @@ namespace tools
|
||||
unsigned get_max_concurrency();
|
||||
|
||||
bool is_local_address(const std::string &address);
|
||||
bool is_privacy_preserving_network(const std::string &address);
|
||||
int vercmp(const char *v0, const char *v1); // returns < 0, 0, > 0, similar to strcmp, but more human friendly than lexical - does not attempt to validate
|
||||
|
||||
bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash);
|
||||
|
||||
@@ -38,6 +38,7 @@ endif()
|
||||
|
||||
set(cryptonote_basic_sources
|
||||
account.cpp
|
||||
connection_context.cpp
|
||||
cryptonote_basic_impl.cpp
|
||||
cryptonote_format_utils.cpp
|
||||
difficulty.cpp
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright (c) 2020, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "connection_context.h"
|
||||
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
std::size_t cryptonote_connection_context::get_max_bytes(const int command) noexcept
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case nodetool::COMMAND_HANDSHAKE_T<cryptonote::CORE_SYNC_DATA>::ID:
|
||||
return 65536;
|
||||
case nodetool::COMMAND_TIMED_SYNC_T<cryptonote::CORE_SYNC_DATA>::ID:
|
||||
return 65536;
|
||||
case nodetool::COMMAND_PING::ID:
|
||||
return 4096;
|
||||
case nodetool::COMMAND_REQUEST_SUPPORT_FLAGS::ID:
|
||||
return 4096;
|
||||
case cryptonote::NOTIFY_NEW_BLOCK::ID:
|
||||
return 1024 * 1024 * 128; // 128 MB (max packet is a bit less than 100 MB though)
|
||||
case cryptonote::NOTIFY_NEW_TRANSACTIONS::ID:
|
||||
return 1024 * 1024 * 128; // 128 MB (max packet is a bit less than 100 MB though)
|
||||
case cryptonote::NOTIFY_REQUEST_GET_OBJECTS::ID:
|
||||
return 1024 * 1024 * 2; // 2 MB
|
||||
case cryptonote::NOTIFY_RESPONSE_GET_OBJECTS::ID:
|
||||
return 1024 * 1024 * 128; // 128 MB (max packet is a bit less than 100 MB though)
|
||||
case cryptonote::NOTIFY_REQUEST_CHAIN::ID:
|
||||
return 512 * 1024; // 512 kB
|
||||
case cryptonote::NOTIFY_RESPONSE_CHAIN_ENTRY::ID:
|
||||
return 1024 * 1024 * 4; // 4 MB
|
||||
case cryptonote::NOTIFY_NEW_FLUFFY_BLOCK::ID:
|
||||
return 1024 * 1024 * 4; // 4 MB, but it does not includes transaction data
|
||||
case cryptonote::NOTIFY_REQUEST_FLUFFY_MISSING_TX::ID:
|
||||
return 1024 * 1024; // 1 MB
|
||||
case cryptonote::NOTIFY_GET_TXPOOL_COMPLEMENT::ID:
|
||||
return 1024 * 1024 * 4; // 4 MB
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return std::numeric_limits<size_t>::max();
|
||||
}
|
||||
} // cryptonote
|
||||
@@ -31,6 +31,7 @@
|
||||
#pragma once
|
||||
#include <unordered_set>
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include "net/net_utils_base.h"
|
||||
#include "copyable_atomic.h"
|
||||
@@ -38,13 +39,12 @@
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
|
||||
{
|
||||
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
|
||||
m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
|
||||
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0),
|
||||
m_expect_response(0) {}
|
||||
m_expect_response(0), m_expect_height(0), m_num_requested(0) {}
|
||||
|
||||
enum state
|
||||
{
|
||||
@@ -55,6 +55,12 @@ namespace cryptonote
|
||||
state_normal
|
||||
};
|
||||
|
||||
static constexpr int handshake_command() noexcept { return 1001; }
|
||||
bool handshake_complete() const noexcept { return m_state != state_before_handshake; }
|
||||
|
||||
//! \return Maximum number of bytes permissible for `command`.
|
||||
static size_t get_max_bytes(int command) noexcept;
|
||||
|
||||
state m_state;
|
||||
std::vector<std::pair<crypto::hash, uint64_t>> m_needed_objects;
|
||||
std::unordered_set<crypto::hash> m_requested_objects;
|
||||
@@ -70,6 +76,9 @@ namespace cryptonote
|
||||
int32_t m_score;
|
||||
int m_expect_response;
|
||||
uint64_t m_expect_height;
|
||||
size_t m_num_requested;
|
||||
epee::copyable_atomic m_new_stripe_notification{0};
|
||||
epee::copyable_atomic m_idle_peer_notification{0};
|
||||
};
|
||||
|
||||
inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
|
||||
|
||||
@@ -124,7 +124,8 @@
|
||||
|
||||
#define CRYPTONOTE_MAX_FRAGMENTS 20 // ~20 * NOISE_BYTES max payload size for covert/noise send
|
||||
|
||||
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT 1000
|
||||
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT 1000
|
||||
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_TX_COUNT 20000
|
||||
|
||||
#define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000
|
||||
#define P2P_LOCAL_GRAY_PEERLIST_LIMIT 5000
|
||||
@@ -197,6 +198,8 @@
|
||||
|
||||
#define RPC_CREDITS_PER_HASH_SCALE ((float)(1<<24))
|
||||
|
||||
#define DNS_BLOCKLIST_LIFETIME (86400 * 8)
|
||||
|
||||
// New constants are intended to go here
|
||||
namespace config
|
||||
{
|
||||
|
||||
@@ -2701,7 +2701,7 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc
|
||||
// find split point between ours and foreign blockchain (or start at
|
||||
// blockchain height <req_start_block>), and return up to max_count FULL
|
||||
// blocks by reference.
|
||||
bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_count) const
|
||||
bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_block_count, size_t max_tx_count) const
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
@@ -2726,8 +2726,8 @@ bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, cons
|
||||
|
||||
db_rtxn_guard rtxn_guard(m_db);
|
||||
total_height = get_current_blockchain_height();
|
||||
blocks.reserve(std::min(std::min(max_count, (size_t)10000), (size_t)(total_height - start_height)));
|
||||
CHECK_AND_ASSERT_MES(m_db->get_blocks_from(start_height, 3, max_count, FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE, blocks, pruned, true, get_miner_tx_hash),
|
||||
blocks.reserve(std::min(std::min(max_block_count, (size_t)10000), (size_t)(total_height - start_height)));
|
||||
CHECK_AND_ASSERT_MES(m_db->get_blocks_from(start_height, 3, max_block_count, max_tx_count, FIND_BLOCKCHAIN_SUPPLEMENT_MAX_SIZE, blocks, pruned, true, get_miner_tx_hash),
|
||||
false, "Error getting blocks");
|
||||
|
||||
return true;
|
||||
@@ -2758,32 +2758,44 @@ void Blockchain::flush_invalid_blocks()
|
||||
m_invalid_blocks.clear();
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::have_block(const crypto::hash& id) const
|
||||
bool Blockchain::have_block_unlocked(const crypto::hash& id, int *where) const
|
||||
{
|
||||
// WARNING: this function does not take m_blockchain_lock, and thus should only call read only
|
||||
// m_db functions which do not depend on one another (ie, no getheight + gethash(height-1), as
|
||||
// well as not accessing class members, even read only (ie, m_invalid_blocks). The caller must
|
||||
// lock if it is otherwise needed.
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
if(m_db->block_exists(id))
|
||||
{
|
||||
LOG_PRINT_L2("block " << id << " found in main chain");
|
||||
if (where) *where = HAVE_BLOCK_MAIN_CHAIN;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(m_db->get_alt_block(id, NULL, NULL))
|
||||
{
|
||||
LOG_PRINT_L2("block " << id << " found in alternative chains");
|
||||
if (where) *where = HAVE_BLOCK_ALT_CHAIN;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(m_invalid_blocks.count(id))
|
||||
{
|
||||
LOG_PRINT_L2("block " << id << " found in m_invalid_blocks");
|
||||
if (where) *where = HAVE_BLOCK_INVALID;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::have_block(const crypto::hash& id, int *where) const
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
return have_block_unlocked(id, where);
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::handle_block_to_main_chain(const block& bl, block_verification_context& bvc, bool notify/* = true*/)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
@@ -4737,6 +4749,8 @@ uint64_t Blockchain::prevalidate_block_hashes(uint64_t height, const std::vector
|
||||
|
||||
CHECK_AND_ASSERT_MES(weights.empty() || weights.size() == hashes.size(), 0, "Unexpected weights size");
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_blockchain_lock);
|
||||
|
||||
// easy case: height >= hashes
|
||||
if (height >= m_blocks_hash_of_hashes.size() * HASH_OF_HASHES_STEP)
|
||||
return hashes.size();
|
||||
@@ -5376,7 +5390,7 @@ void Blockchain::cancel()
|
||||
}
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
static const char expected_block_hashes_hash[] = "9df68e5d89dc3789768c4701c5dea3fd32c1df22acc439c29b775eb54cefbf29";
|
||||
static const char expected_block_hashes_hash[] = "b198c2514bed71ca0a43cba6590090068daf6d207b351d8a4c7d0f0f791c095f";
|
||||
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
|
||||
{
|
||||
if (get_checkpoints == nullptr || !m_fast_sync)
|
||||
|
||||
@@ -376,10 +376,12 @@ namespace cryptonote
|
||||
* for a block with the given hash
|
||||
*
|
||||
* @param id the hash to search for
|
||||
* @param where the type of block, if non NULL
|
||||
*
|
||||
* @return true if the block is known, else false
|
||||
*/
|
||||
bool have_block(const crypto::hash& id) const;
|
||||
bool have_block_unlocked(const crypto::hash& id, int *where = NULL) const;
|
||||
bool have_block(const crypto::hash& id, int *where = NULL) const;
|
||||
|
||||
/**
|
||||
* @brief gets the total number of transactions on the main chain
|
||||
@@ -464,11 +466,12 @@ namespace cryptonote
|
||||
* @param total_height return-by-reference our current blockchain height
|
||||
* @param start_height return-by-reference the height of the first block returned
|
||||
* @param pruned whether to return full or pruned tx blobs
|
||||
* @param max_count the max number of blocks to get
|
||||
* @param max_block_count the max number of blocks to get
|
||||
* @param max_tx_count the max number of txes to get (it can get overshot by the last block's number of txes minus 1)
|
||||
*
|
||||
* @return true if a block found in common or req_start_block specified, else false
|
||||
*/
|
||||
bool find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_count) const;
|
||||
bool find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_block_count, size_t max_tx_count) const;
|
||||
|
||||
/**
|
||||
* @brief retrieves a set of blocks and their transactions, and possibly other transactions
|
||||
|
||||
@@ -1406,9 +1406,9 @@ namespace cryptonote
|
||||
return m_blockchain_storage.find_blockchain_supplement(qblock_ids, clip_pruned, resp);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_count) const
|
||||
bool core::find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_block_count, size_t max_tx_count) const
|
||||
{
|
||||
return m_blockchain_storage.find_blockchain_supplement(req_start_block, qblock_ids, blocks, total_height, start_height, pruned, get_miner_tx_hash, max_count);
|
||||
return m_blockchain_storage.find_blockchain_supplement(req_start_block, qblock_ids, blocks, total_height, start_height, pruned, get_miner_tx_hash, max_block_count, max_tx_count);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMAND_RPC_GET_OUTPUTS_BIN::response& res) const
|
||||
@@ -1625,9 +1625,14 @@ namespace cryptonote
|
||||
return m_mempool.get_transactions_count(include_sensitive_txes);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::have_block(const crypto::hash& id) const
|
||||
bool core::have_block_unlocked(const crypto::hash& id, int *where) const
|
||||
{
|
||||
return m_blockchain_storage.have_block(id);
|
||||
return m_blockchain_storage.have_block_unlocked(id, where);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::have_block(const crypto::hash& id, int *where) const
|
||||
{
|
||||
return m_blockchain_storage.have_block(id, where);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::parse_tx_from_blob(transaction& tx, crypto::hash& tx_hash, const blobdata& blob) const
|
||||
|
||||
@@ -55,6 +55,8 @@
|
||||
PUSH_WARNINGS
|
||||
DISABLE_VS_WARNINGS(4355)
|
||||
|
||||
enum { HAVE_BLOCK_MAIN_CHAIN, HAVE_BLOCK_ALT_CHAIN, HAVE_BLOCK_INVALID };
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
struct test_options {
|
||||
@@ -543,7 +545,8 @@ namespace cryptonote
|
||||
*
|
||||
* @note see Blockchain::have_block
|
||||
*/
|
||||
bool have_block(const crypto::hash& id) const;
|
||||
bool have_block_unlocked(const crypto::hash& id, int *where = NULL) const;
|
||||
bool have_block(const crypto::hash& id, int *where = NULL) const;
|
||||
|
||||
/**
|
||||
* @copydoc Blockchain::get_short_chain_history
|
||||
@@ -564,7 +567,7 @@ namespace cryptonote
|
||||
*
|
||||
* @note see Blockchain::find_blockchain_supplement(const uint64_t, const std::list<crypto::hash>&, std::vector<std::pair<cryptonote::blobdata, std::vector<transaction> > >&, uint64_t&, uint64_t&, size_t) const
|
||||
*/
|
||||
bool find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_count) const;
|
||||
bool find_blockchain_supplement(const uint64_t req_start_block, const std::list<crypto::hash>& qblock_ids, std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > >& blocks, uint64_t& total_height, uint64_t& start_height, bool pruned, bool get_miner_tx_hash, size_t max_block_count, size_t max_tx_count) const;
|
||||
|
||||
/**
|
||||
* @copydoc Blockchain::get_tx_outputs_gindexs
|
||||
|
||||
@@ -44,10 +44,10 @@ namespace cryptonote
|
||||
typedef std::pair<uint64_t, rct::ctkey> output_entry;
|
||||
|
||||
std::vector<output_entry> outputs; //index + key + optional ringct commitment
|
||||
size_t real_output; //index in outputs vector of real output_entry
|
||||
uint64_t real_output; //index in outputs vector of real output_entry
|
||||
crypto::public_key real_out_tx_key; //incoming real tx public key
|
||||
std::vector<crypto::public_key> real_out_additional_tx_keys; //incoming real tx additional public keys
|
||||
size_t real_output_in_tx_index; //index in transaction outputs vector
|
||||
uint64_t real_output_in_tx_index; //index in transaction outputs vector
|
||||
uint64_t amount; //money
|
||||
bool rct; //true if the output is rct
|
||||
rct::key mask; //ringct amount mask
|
||||
|
||||
@@ -116,6 +116,8 @@ namespace cryptonote
|
||||
std::string get_peers_overview() const;
|
||||
std::pair<uint32_t, uint32_t> get_next_needed_pruning_stripe() const;
|
||||
bool needs_new_sync_connections() const;
|
||||
bool is_busy_syncing();
|
||||
|
||||
private:
|
||||
//----------------- commands handlers ----------------------------------------------
|
||||
int handle_notify_new_block(int command, NOTIFY_NEW_BLOCK::request& arg, cryptonote_connection_context& context);
|
||||
@@ -147,7 +149,7 @@ namespace cryptonote
|
||||
bool update_sync_search();
|
||||
int try_add_next_blocks(cryptonote_connection_context &context);
|
||||
void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe);
|
||||
void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
|
||||
size_t skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const;
|
||||
bool request_txpool_complement(cryptonote_connection_context &context);
|
||||
void hit_score(cryptonote_connection_context &context, int32_t score);
|
||||
|
||||
|
||||
@@ -137,7 +137,42 @@ namespace cryptonote
|
||||
CHECK_AND_ASSERT_MES_CC( context.m_callback_request_count > 0, false, "false callback fired, but context.m_callback_request_count=" << context.m_callback_request_count);
|
||||
--context.m_callback_request_count;
|
||||
|
||||
if(context.m_state == cryptonote_connection_context::state_synchronizing)
|
||||
uint32_t notified = true;
|
||||
if (context.m_idle_peer_notification.compare_exchange_strong(notified, not notified))
|
||||
{
|
||||
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
|
||||
{
|
||||
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||
const boost::posix_time::time_duration dt = now - context.m_last_request_time;
|
||||
const auto ms = dt.total_microseconds();
|
||||
if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
|
||||
{
|
||||
if (context.m_score-- >= 0)
|
||||
{
|
||||
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
|
||||
context.m_last_request_time = boost::date_time::not_a_date_time;
|
||||
context.m_expect_response = 0;
|
||||
context.m_expect_height = 0;
|
||||
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
|
||||
}
|
||||
else
|
||||
{
|
||||
MINFO(context << "dropping idle peer with negative score");
|
||||
drop_connection_with_score(context, context.m_expect_response == 0 ? 1 : 5, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notified = true;
|
||||
if (context.m_new_stripe_notification.compare_exchange_strong(notified, not notified))
|
||||
{
|
||||
if (context.m_state == cryptonote_connection_context::state_normal)
|
||||
context.m_state = cryptonote_connection_context::state_synchronizing;
|
||||
}
|
||||
|
||||
if(context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time == boost::posix_time::not_a_date_time)
|
||||
{
|
||||
NOTIFY_REQUEST_CHAIN::request r = {};
|
||||
context.m_needed_objects.clear();
|
||||
@@ -409,6 +444,7 @@ namespace cryptonote
|
||||
++context.m_callback_request_count;
|
||||
m_p2p->request_callback(context);
|
||||
MLOG_PEER_STATE("requesting callback");
|
||||
context.m_num_requested = 0;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1687,7 +1723,7 @@ skip:
|
||||
const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
|
||||
if (stripe && peer_stripe && peer_stripe != stripe)
|
||||
return true;
|
||||
context.m_state = cryptonote_connection_context::state_synchronizing;
|
||||
context.m_new_stripe_notification = true;
|
||||
LOG_PRINT_CCONTEXT_L2("requesting callback");
|
||||
++context.m_callback_request_count;
|
||||
m_p2p->request_callback(context);
|
||||
@@ -1710,7 +1746,6 @@ skip:
|
||||
bool t_cryptonote_protocol_handler<t_core>::kick_idle_peers()
|
||||
{
|
||||
MTRACE("Checking for idle peers...");
|
||||
std::vector<std::pair<boost::uuids::uuid, unsigned>> idle_peers;
|
||||
m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool
|
||||
{
|
||||
if (context.m_state == cryptonote_connection_context::state_synchronizing && context.m_last_request_time != boost::date_time::not_a_date_time)
|
||||
@@ -1720,36 +1755,16 @@ skip:
|
||||
const auto ms = dt.total_microseconds();
|
||||
if (ms > IDLE_PEER_KICK_TIME || (context.m_expect_response && ms > NON_RESPONSIVE_PEER_KICK_TIME))
|
||||
{
|
||||
if (context.m_score-- >= 0)
|
||||
{
|
||||
MINFO(context << " kicking idle peer, last update " << (dt.total_microseconds() / 1.e6) << " seconds ago, expecting " << (int)context.m_expect_response);
|
||||
LOG_PRINT_CCONTEXT_L2("requesting callback");
|
||||
context.m_last_request_time = boost::date_time::not_a_date_time;
|
||||
context.m_expect_response = 0;
|
||||
context.m_expect_height = 0;
|
||||
context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download
|
||||
++context.m_callback_request_count;
|
||||
m_p2p->request_callback(context);
|
||||
}
|
||||
else
|
||||
{
|
||||
idle_peers.push_back(std::make_pair(context.m_connection_id, context.m_expect_response == 0 ? 1 : 5));
|
||||
}
|
||||
context.m_idle_peer_notification = true;
|
||||
LOG_PRINT_CCONTEXT_L2("requesting callback");
|
||||
++context.m_callback_request_count;
|
||||
m_p2p->request_callback(context);
|
||||
MLOG_PEER_STATE("requesting callback");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
for (const auto &e: idle_peers)
|
||||
{
|
||||
const auto &uuid = e.first;
|
||||
m_p2p->for_connection(uuid, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
MINFO(ctx << "dropping idle peer with negative score");
|
||||
drop_connection_with_score(ctx, e.second, false);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1990,7 +2005,7 @@ skip:
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const
|
||||
size_t t_cryptonote_protocol_handler<t_core>::skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const
|
||||
{
|
||||
// take out blocks we already have
|
||||
size_t skip = 0;
|
||||
@@ -2007,6 +2022,7 @@ skip:
|
||||
MDEBUG(context << "skipping " << skip << "/" << context.m_needed_objects.size() << " blocks");
|
||||
context.m_needed_objects = std::vector<std::pair<crypto::hash, uint64_t>>(context.m_needed_objects.begin() + skip, context.m_needed_objects.end());
|
||||
}
|
||||
return skip;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
@@ -2060,7 +2076,17 @@ skip:
|
||||
const size_t block_queue_size_threshold = m_block_download_max_size ? m_block_download_max_size : BLOCK_QUEUE_SIZE_THRESHOLD;
|
||||
bool queue_proceed = nspans < BLOCK_QUEUE_NSPANS_THRESHOLD || size < block_queue_size_threshold;
|
||||
// get rid of blocks we already requested, or already have
|
||||
skip_unneeded_hashes(context, true);
|
||||
if (skip_unneeded_hashes(context, true) && context.m_needed_objects.empty() && context.m_num_requested == 0)
|
||||
{
|
||||
if (context.m_remote_blockchain_height > m_block_queue.get_next_needed_height(bc_height))
|
||||
{
|
||||
MERROR(context << "Nothing we can request from this peer, and we did not request anything previously");
|
||||
return false;
|
||||
}
|
||||
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
return true;
|
||||
}
|
||||
uint64_t next_needed_height = m_block_queue.get_next_needed_height(bc_height);
|
||||
uint64_t next_block_height;
|
||||
if (context.m_needed_objects.empty())
|
||||
@@ -2196,7 +2222,17 @@ skip:
|
||||
context.m_last_response_height = 0;
|
||||
goto skip;
|
||||
}
|
||||
skip_unneeded_hashes(context, false);
|
||||
if (skip_unneeded_hashes(context, false) && context.m_needed_objects.empty() && context.m_num_requested == 0)
|
||||
{
|
||||
if (context.m_remote_blockchain_height > m_block_queue.get_next_needed_height(m_core.get_current_blockchain_height()))
|
||||
{
|
||||
MERROR(context << "Nothing we can request from this peer, and we did not request anything previously");
|
||||
return false;
|
||||
}
|
||||
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint64_t first_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
|
||||
static const uint64_t bp_fork_height = m_core.get_earliest_ideal_height_for_version(8);
|
||||
@@ -2293,35 +2329,22 @@ skip:
|
||||
<< "/" << tools::get_pruning_stripe(span.first + span.second - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)
|
||||
<< ", ours " << tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed()) << ", peer stripe " << tools::get_pruning_stripe(context.m_pruning_seed));
|
||||
|
||||
context.m_num_requested += req.blocks.size();
|
||||
post_notify<NOTIFY_REQUEST_GET_OBJECTS>(req, context);
|
||||
MLOG_PEER_STATE("requesting objects");
|
||||
return true;
|
||||
}
|
||||
|
||||
// if we're still around, we might be at a point where the peer is pruned, so we could either
|
||||
// drop it to make space for other peers, or ask for a span further down the line
|
||||
const uint32_t next_stripe = get_next_needed_pruning_stripe().first;
|
||||
const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
|
||||
const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
|
||||
if (!(m_sync_pruned_blocks && peer_stripe == local_stripe) && next_stripe && peer_stripe && next_stripe != peer_stripe)
|
||||
// we can do nothing, so drop this peer to make room for others unless we think we've downloaded all we need
|
||||
const uint64_t blockchain_height = m_core.get_current_blockchain_height();
|
||||
if (std::max(blockchain_height, m_block_queue.get_next_needed_height(blockchain_height)) >= m_core.get_target_blockchain_height())
|
||||
{
|
||||
// at this point, we have to either close the connection, or start getting blocks past the
|
||||
// current point, or become dormant
|
||||
MDEBUG(context << "this peer is pruned at seed " << epee::string_tools::to_string_hex(context.m_pruning_seed) <<
|
||||
", next stripe needed is " << next_stripe);
|
||||
if (!context.m_is_income)
|
||||
{
|
||||
if (should_drop_connection(context, next_stripe))
|
||||
{
|
||||
m_p2p->add_used_stripe_peer(context);
|
||||
return false; // drop outgoing connections
|
||||
}
|
||||
}
|
||||
// we'll get back stuck waiting for the go ahead
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
MLOG_PEER_STATE("Nothing to do for now, switching to normal state");
|
||||
return true;
|
||||
}
|
||||
MLOG_PEER_STATE("We can download nothing from this peer, dropping");
|
||||
return false;
|
||||
}
|
||||
|
||||
skip:
|
||||
@@ -2561,17 +2584,6 @@ skip:
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unordered_set<crypto::hash> hashes;
|
||||
for (const auto &h: arg.m_block_ids)
|
||||
{
|
||||
if (!hashes.insert(h).second)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent duplicate block, dropping connection");
|
||||
drop_connection(context, true, false);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t n_use_blocks = m_core.prevalidate_block_hashes(arg.start_height, arg.m_block_ids, arg.m_block_weights);
|
||||
if (n_use_blocks == 0 || n_use_blocks + HASH_OF_HASHES_STEP <= arg.m_block_ids.size())
|
||||
{
|
||||
@@ -2583,18 +2595,74 @@ skip:
|
||||
context.m_needed_objects.clear();
|
||||
uint64_t added = 0;
|
||||
std::unordered_set<crypto::hash> blocks_found;
|
||||
bool first = true;
|
||||
bool expect_unknown = false;
|
||||
for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
|
||||
{
|
||||
if (!blocks_found.insert(arg.m_block_ids[i]).second)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Duplicate blocks in chain entry response, dropping connection");
|
||||
drop_connection(context, true, false);
|
||||
drop_connection_with_score(context, 5, false);
|
||||
return 1;
|
||||
}
|
||||
int where;
|
||||
const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where);
|
||||
if (first)
|
||||
{
|
||||
if (!have_block && !m_block_queue.requested(arg.m_block_ids[i]) && !m_block_queue.have(arg.m_block_ids[i]))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection");
|
||||
drop_connection_with_score(context, 5, false);
|
||||
return 1;
|
||||
}
|
||||
if (!have_block)
|
||||
expect_unknown = true;
|
||||
}
|
||||
if (!first)
|
||||
{
|
||||
// after the first, blocks may be known or unknown, but if they are known,
|
||||
// they should be at the same height if on the main chain
|
||||
if (have_block)
|
||||
{
|
||||
switch (where)
|
||||
{
|
||||
default:
|
||||
case HAVE_BLOCK_INVALID:
|
||||
LOG_ERROR_CCONTEXT("Block is invalid or known without known type, dropping connection");
|
||||
drop_connection(context, true, false);
|
||||
return 1;
|
||||
case HAVE_BLOCK_MAIN_CHAIN:
|
||||
if (expect_unknown)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
|
||||
drop_connection_with_score(context, 5, false);
|
||||
return 1;
|
||||
}
|
||||
if (m_core.get_block_id_by_height(arg.start_height + i) != arg.m_block_ids[i])
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Block is on the main chain, but not at the expected height, dropping connection");
|
||||
drop_connection_with_score(context, 5, false);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case HAVE_BLOCK_ALT_CHAIN:
|
||||
if (expect_unknown)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Block is on the main chain, but we did not expect a known block, dropping connection");
|
||||
drop_connection_with_score(context, 5, false);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
expect_unknown = true;
|
||||
}
|
||||
const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
|
||||
context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
|
||||
if (++added == n_use_blocks)
|
||||
break;
|
||||
first = false;
|
||||
}
|
||||
context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
|
||||
|
||||
@@ -2608,6 +2676,7 @@ skip:
|
||||
if (arg.total_height > m_core.get_target_blockchain_height())
|
||||
m_core.set_target_blockchain_height(arg.total_height);
|
||||
|
||||
context.m_num_requested = 0;
|
||||
return 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -2624,6 +2693,7 @@ skip:
|
||||
std::vector<std::pair<epee::net_utils::zone, boost::uuids::uuid>> fullConnections, fluffyConnections;
|
||||
m_p2p->for_each_connection([this, &exclude_context, &fullConnections, &fluffyConnections](connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)
|
||||
{
|
||||
// peer_id also filters out connections before handshake
|
||||
if (peer_id && exclude_context.m_connection_id != context.m_connection_id && context.m_remote_address.get_zone() == epee::net_utils::zone::public_)
|
||||
{
|
||||
if(m_core.fluffy_blocks_enabled() && (support_flags & P2P_SUPPORT_FLAG_FLUFFY_BLOCKS))
|
||||
@@ -2771,6 +2841,13 @@ skip:
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::is_busy_syncing()
|
||||
{
|
||||
const boost::unique_lock<boost::mutex> sync{m_sync_lock, boost::try_to_lock};
|
||||
return !sync.owns_lock();
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::drop_connection_with_score(cryptonote_connection_context &context, unsigned score, bool flush_all_spans)
|
||||
{
|
||||
LOG_DEBUG_CC(context, "dropping connection id " << context.m_connection_id << " (pruning seed " <<
|
||||
|
||||
@@ -442,7 +442,7 @@ namespace levin
|
||||
zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context)
|
||||
{
|
||||
// When i2p/tor, only fluff to outbound connections
|
||||
if (source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income))
|
||||
if (context.handshake_complete() && source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income))
|
||||
{
|
||||
if (context.fluff_txs.empty())
|
||||
context.flush_time = now + (context.m_is_income ? in_duration() : out_duration());
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "common/dns_utils.h"
|
||||
#include "common/command_line.h"
|
||||
#include "net/parse.h"
|
||||
#include "daemon/command_parser_executor.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
@@ -585,7 +586,6 @@ bool t_command_parser_executor::show_bans(const std::vector<std::string>& args)
|
||||
bool t_command_parser_executor::ban(const std::vector<std::string>& args)
|
||||
{
|
||||
if (args.size() != 1 && args.size() != 2) return false;
|
||||
std::string ip = args[0];
|
||||
time_t seconds = P2P_IP_BLOCKTIME;
|
||||
if (args.size() > 1)
|
||||
{
|
||||
@@ -602,7 +602,51 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return m_executor.ban(ip, seconds);
|
||||
if (boost::starts_with(args[0], "@"))
|
||||
{
|
||||
const std::string ban_list = args[0].substr(1);
|
||||
|
||||
try
|
||||
{
|
||||
const boost::filesystem::path ban_list_path(ban_list);
|
||||
boost::system::error_code ec;
|
||||
if (!boost::filesystem::exists(ban_list_path, ec))
|
||||
{
|
||||
std::cout << "Can't find ban list file " + ban_list + " - " + ec.message() << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
std::ifstream ifs(ban_list_path.string());
|
||||
for (std::string line; std::getline(ifs, line); )
|
||||
{
|
||||
auto subnet = net::get_ipv4_subnet_address(line);
|
||||
if (subnet)
|
||||
{
|
||||
ret &= m_executor.ban(subnet->str(), seconds);
|
||||
continue;
|
||||
}
|
||||
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0);
|
||||
if (parsed_addr)
|
||||
{
|
||||
ret &= m_executor.ban(parsed_addr->host_str(), seconds);
|
||||
continue;
|
||||
}
|
||||
std::cout << "Invalid IP address or IPv4 subnet: " << line << std::endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cout << "Error loading ban list: " << e.what() << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string ip = args[0];
|
||||
return m_executor.ban(ip, seconds);
|
||||
}
|
||||
}
|
||||
|
||||
bool t_command_parser_executor::unban(const std::vector<std::string>& args)
|
||||
|
||||
@@ -233,8 +233,8 @@ t_command_server::t_command_server(
|
||||
m_command_lookup.set_handler(
|
||||
"ban"
|
||||
, std::bind(&t_command_parser_executor::ban, &m_parser, p::_1)
|
||||
, "ban <IP> [<seconds>]"
|
||||
, "Ban a given <IP> for a given amount of <seconds>."
|
||||
, "ban [<IP>|@<filename>] [<seconds>]"
|
||||
, "Ban a given <IP> or list of IPs from a file for a given amount of <seconds>."
|
||||
);
|
||||
m_command_lookup.set_handler(
|
||||
"unban"
|
||||
|
||||
@@ -191,6 +191,9 @@ bool t_rpc_command_executor::print_peer_list(bool white, bool gray, size_t limit
|
||||
cryptonote::COMMAND_RPC_GET_PEER_LIST::response res;
|
||||
|
||||
std::string failure_message = "Couldn't retrieve peer list";
|
||||
|
||||
req.include_blocked = true;
|
||||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->rpc_request(req, res, "/get_peer_list", failure_message.c_str()))
|
||||
@@ -237,6 +240,7 @@ bool t_rpc_command_executor::print_peer_list_stats() {
|
||||
std::string failure_message = "Couldn't retrieve peer list";
|
||||
|
||||
req.public_only = false;
|
||||
req.include_blocked = true;
|
||||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
|
||||
@@ -365,15 +365,14 @@ namespace trezor {
|
||||
void device_trezor_base::device_state_initialize_unsafe()
|
||||
{
|
||||
require_connected();
|
||||
std::string tmp_session_id;
|
||||
auto initMsg = std::make_shared<messages::management::Initialize>();
|
||||
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
|
||||
memwipe(&tmp_session_id[0], tmp_session_id.size());
|
||||
if (initMsg->has_session_id())
|
||||
memwipe(&(*initMsg->mutable_session_id())[0], initMsg->mutable_session_id()->size());
|
||||
});
|
||||
|
||||
if(!m_device_session_id.empty()) {
|
||||
tmp_session_id.assign(m_device_session_id.data(), m_device_session_id.size());
|
||||
initMsg->set_allocated_session_id(&tmp_session_id);
|
||||
initMsg->set_allocated_session_id(new std::string(m_device_session_id.data(), m_device_session_id.size()));
|
||||
}
|
||||
|
||||
m_features = this->client_exchange<messages::management::Features>(initMsg);
|
||||
@@ -382,8 +381,6 @@ namespace trezor {
|
||||
} else {
|
||||
m_device_session_id.clear();
|
||||
}
|
||||
|
||||
initMsg->release_session_id();
|
||||
}
|
||||
|
||||
void device_trezor_base::device_state_reset()
|
||||
@@ -453,18 +450,14 @@ namespace trezor {
|
||||
pin = m_pin;
|
||||
}
|
||||
|
||||
std::string pin_field;
|
||||
messages::common::PinMatrixAck m;
|
||||
if (pin) {
|
||||
pin_field.assign(pin->data(), pin->size());
|
||||
m.set_allocated_pin(&pin_field);
|
||||
m.set_allocated_pin(new std::string(pin->data(), pin->size()));
|
||||
}
|
||||
|
||||
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
|
||||
m.release_pin();
|
||||
if (!pin_field.empty()){
|
||||
memwipe(&pin_field[0], pin_field.size());
|
||||
}
|
||||
if (m.has_pin())
|
||||
memwipe(&(*m.mutable_pin())[0], m.mutable_pin()->size());
|
||||
});
|
||||
|
||||
resp = call_raw(&m);
|
||||
@@ -499,7 +492,6 @@ namespace trezor {
|
||||
boost::optional<epee::wipeable_string> passphrase;
|
||||
TREZOR_CALLBACK_GET(passphrase, on_passphrase_request, on_device);
|
||||
|
||||
std::string passphrase_field;
|
||||
messages::common::PassphraseAck m;
|
||||
m.set_on_device(on_device);
|
||||
if (!on_device) {
|
||||
@@ -512,16 +504,13 @@ namespace trezor {
|
||||
}
|
||||
|
||||
if (passphrase) {
|
||||
passphrase_field.assign(passphrase->data(), passphrase->size());
|
||||
m.set_allocated_passphrase(&passphrase_field);
|
||||
m.set_allocated_passphrase(new std::string(passphrase->data(), passphrase->size()));
|
||||
}
|
||||
}
|
||||
|
||||
const auto data_cleaner = epee::misc_utils::create_scope_leave_handler([&]() {
|
||||
m.release_passphrase();
|
||||
if (!passphrase_field.empty()){
|
||||
memwipe(&passphrase_field[0], passphrase_field.size());
|
||||
}
|
||||
if (m.has_passphrase())
|
||||
memwipe(&(m.mutable_passphrase())[0], m.mutable_passphrase()->size());
|
||||
});
|
||||
|
||||
resp = call_raw(&m);
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace trezor {
|
||||
|
||||
// Scoped session closer
|
||||
BOOST_SCOPE_EXIT_ALL(&, this) {
|
||||
if (open_session){
|
||||
if (open_session && this->get_transport()){
|
||||
this->get_transport()->close();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -502,21 +502,9 @@ namespace tx {
|
||||
}
|
||||
|
||||
void Signer::compute_integrated_indices(TsxData * tsx_data){
|
||||
if (m_aux_data == nullptr || m_aux_data->tx_recipients.empty()){
|
||||
return;
|
||||
}
|
||||
|
||||
auto & chg = tsx_data->change_dts();
|
||||
std::string change_hash = hash_addr(&chg.addr(), chg.amount(), chg.is_subaddress());
|
||||
|
||||
std::vector<uint32_t> integrated_indices;
|
||||
std::set<std::string> integrated_hashes;
|
||||
for (auto & cur : m_aux_data->tx_recipients){
|
||||
if (!cur.has_payment_id){
|
||||
continue;
|
||||
}
|
||||
integrated_hashes.emplace(hash_addr(&cur.address.m_spend_public_key, &cur.address.m_view_public_key));
|
||||
}
|
||||
|
||||
ssize_t idx = -1;
|
||||
for (auto & cur : tsx_data->outputs()){
|
||||
@@ -527,8 +515,7 @@ namespace tx {
|
||||
continue;
|
||||
}
|
||||
|
||||
c_hash = hash_addr(&cur.addr());
|
||||
if (integrated_hashes.find(c_hash) != integrated_hashes.end()){
|
||||
if (cur.is_integrated()){
|
||||
integrated_indices.push_back((uint32_t)idx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,7 @@ namespace nodetool
|
||||
const command_line::arg_descriptor<std::string> arg_ban_list = {"ban-list", "Specify ban list file, one IP address per line"};
|
||||
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port = {"hide-my-port", "Do not announce yourself as peerlist candidate", false, true};
|
||||
const command_line::arg_descriptor<bool> arg_no_sync = {"no-sync", "Don't synchronize the blockchain with other peers", false};
|
||||
const command_line::arg_descriptor<bool> arg_enable_dns_blocklist = {"enable-dns-blocklist", "Apply realtime blocklist from DNS", false};
|
||||
|
||||
const command_line::arg_descriptor<bool> arg_no_igd = {"no-igd", "Disable UPnP port mapping"};
|
||||
const command_line::arg_descriptor<std::string> arg_igd = {"igd", "UPnP port mapping (disabled, enabled, delayed)", "delayed"};
|
||||
|
||||
+7
-1
@@ -139,6 +139,7 @@ namespace nodetool
|
||||
|
||||
typedef COMMAND_HANDSHAKE_T<typename t_payload_net_handler::payload_type> COMMAND_HANDSHAKE;
|
||||
typedef COMMAND_TIMED_SYNC_T<typename t_payload_net_handler::payload_type> COMMAND_TIMED_SYNC;
|
||||
static_assert(p2p_connection_context::handshake_command() == COMMAND_HANDSHAKE::ID, "invalid handshake command id");
|
||||
|
||||
typedef epee::net_utils::boosted_tcp_server<epee::levin::async_protocol_handler<p2p_connection_context>> net_server;
|
||||
|
||||
@@ -287,7 +288,7 @@ namespace nodetool
|
||||
uint32_t get_max_out_public_peers() const;
|
||||
void change_max_in_public_peers(size_t count);
|
||||
uint32_t get_max_in_public_peers() const;
|
||||
virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME);
|
||||
virtual bool block_host(epee::net_utils::network_address address, time_t seconds = P2P_IP_BLOCKTIME, bool add_only = false);
|
||||
virtual bool unblock_host(const epee::net_utils::network_address &address);
|
||||
virtual bool block_subnet(const epee::net_utils::ipv4_network_subnet &subnet, time_t seconds = P2P_IP_BLOCKTIME);
|
||||
virtual bool unblock_subnet(const epee::net_utils::ipv4_network_subnet &subnet);
|
||||
@@ -369,6 +370,7 @@ namespace nodetool
|
||||
bool peer_sync_idle_maker();
|
||||
bool do_handshake_with_peer(peerid_type& pi, p2p_connection_context& context, bool just_take_peerlist = false);
|
||||
bool do_peer_timed_sync(const epee::net_utils::connection_context_base& context, peerid_type peer_id);
|
||||
bool update_dns_blocklist();
|
||||
|
||||
bool make_new_connection_from_anchor_peerlist(const std::vector<anchor_peerlist_entry>& anchor_peerlist);
|
||||
bool make_new_connection_from_peerlist(network_zone& zone, bool use_white_list);
|
||||
@@ -474,6 +476,7 @@ namespace nodetool
|
||||
epee::math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval;
|
||||
epee::math_helper::once_a_time_seconds<60> m_gray_peerlist_housekeeping_interval;
|
||||
epee::math_helper::once_a_time_seconds<3600, false> m_incoming_connections_interval;
|
||||
epee::math_helper::once_a_time_seconds<7000> m_dns_blocklist_interval;
|
||||
|
||||
std::list<epee::net_utils::network_address> m_priority_peers;
|
||||
std::vector<epee::net_utils::network_address> m_exclusive_peers;
|
||||
@@ -512,6 +515,8 @@ namespace nodetool
|
||||
cryptonote::network_type m_nettype;
|
||||
|
||||
epee::net_utils::ssl_support_t m_ssl_support;
|
||||
|
||||
bool m_enable_dns_blocklist;
|
||||
};
|
||||
|
||||
const int64_t default_limit_up = P2P_DEFAULT_LIMIT_RATE_UP; // kB/s
|
||||
@@ -533,6 +538,7 @@ namespace nodetool
|
||||
extern const command_line::arg_descriptor<std::string> arg_ban_list;
|
||||
extern const command_line::arg_descriptor<bool> arg_p2p_hide_my_port;
|
||||
extern const command_line::arg_descriptor<bool> arg_no_sync;
|
||||
extern const command_line::arg_descriptor<bool> arg_enable_dns_blocklist;
|
||||
|
||||
extern const command_line::arg_descriptor<bool> arg_no_igd;
|
||||
extern const command_line::arg_descriptor<std::string> arg_igd;
|
||||
|
||||
+93
-12
@@ -37,6 +37,7 @@
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
@@ -120,6 +121,7 @@ namespace nodetool
|
||||
command_line::add_arg(desc, arg_ban_list);
|
||||
command_line::add_arg(desc, arg_p2p_hide_my_port);
|
||||
command_line::add_arg(desc, arg_no_sync);
|
||||
command_line::add_arg(desc, arg_enable_dns_blocklist);
|
||||
command_line::add_arg(desc, arg_no_igd);
|
||||
command_line::add_arg(desc, arg_igd);
|
||||
command_line::add_arg(desc, arg_out_peers);
|
||||
@@ -226,12 +228,13 @@ namespace nodetool
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::block_host(epee::net_utils::network_address addr, time_t seconds)
|
||||
bool node_server<t_payload_net_handler>::block_host(epee::net_utils::network_address addr, time_t seconds, bool add_only)
|
||||
{
|
||||
if(!addr.is_blockable())
|
||||
return false;
|
||||
|
||||
const time_t now = time(nullptr);
|
||||
bool added = false;
|
||||
|
||||
CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
|
||||
time_t limit;
|
||||
@@ -240,7 +243,14 @@ namespace nodetool
|
||||
else
|
||||
limit = now + seconds;
|
||||
const std::string host_str = addr.host_str();
|
||||
m_blocked_hosts[host_str] = limit;
|
||||
auto it = m_blocked_hosts.find(host_str);
|
||||
if (it == m_blocked_hosts.end())
|
||||
{
|
||||
m_blocked_hosts[host_str] = limit;
|
||||
added = true;
|
||||
}
|
||||
else if (it->second < limit || !add_only)
|
||||
it->second = limit;
|
||||
|
||||
// drop any connection to that address. This should only have to look into
|
||||
// the zone related to the connection, but really make sure everything is
|
||||
@@ -260,6 +270,8 @@ namespace nodetool
|
||||
peerlist_entry pe{};
|
||||
pe.adr = addr;
|
||||
zone.second.m_peerlist.remove_from_peer_white(pe);
|
||||
zone.second.m_peerlist.remove_from_peer_gray(pe);
|
||||
zone.second.m_peerlist.remove_from_peer_anchor(addr);
|
||||
|
||||
for (const auto &c: conns)
|
||||
zone.second.m_net_server.get_config_object().close(c);
|
||||
@@ -267,7 +279,10 @@ namespace nodetool
|
||||
conns.clear();
|
||||
}
|
||||
|
||||
MCLOG_CYAN(el::Level::Info, "global", "Host " << host_str << " blocked.");
|
||||
if (added)
|
||||
MCLOG_CYAN(el::Level::Info, "global", "Host " << host_str << " blocked.");
|
||||
else
|
||||
MINFO("Host " << host_str << " block time updated.");
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
@@ -481,13 +496,19 @@ namespace nodetool
|
||||
std::istringstream iss(banned_ips);
|
||||
for (std::string line; std::getline(iss, line); )
|
||||
{
|
||||
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0);
|
||||
if (!parsed_addr)
|
||||
auto subnet = net::get_ipv4_subnet_address(line);
|
||||
if (subnet)
|
||||
{
|
||||
MERROR("Invalid IP address: " << line << " - " << parsed_addr.error());
|
||||
block_subnet(*subnet, std::numeric_limits<time_t>::max());
|
||||
continue;
|
||||
}
|
||||
block_host(*parsed_addr, std::numeric_limits<time_t>::max());
|
||||
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(line, 0);
|
||||
if (parsed_addr)
|
||||
{
|
||||
block_host(*parsed_addr, std::numeric_limits<time_t>::max());
|
||||
continue;
|
||||
}
|
||||
MERROR("Invalid IP address or IPv4 subnet: " << line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,6 +518,8 @@ namespace nodetool
|
||||
if (command_line::has_arg(vm, arg_no_sync))
|
||||
m_payload_handler.set_no_sync(true);
|
||||
|
||||
m_enable_dns_blocklist = command_line::get_arg(vm, arg_enable_dns_blocklist);
|
||||
|
||||
if ( !set_max_out_peers(public_zone, command_line::get_arg(vm, arg_out_peers) ) )
|
||||
return false;
|
||||
else
|
||||
@@ -1971,6 +1994,61 @@ namespace nodetool
|
||||
m_gray_peerlist_housekeeping_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::gray_peerlist_housekeeping, this));
|
||||
m_peerlist_store_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::store_config, this));
|
||||
m_incoming_connections_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::check_incoming_connections, this));
|
||||
m_dns_blocklist_interval.do_call(boost::bind(&node_server<t_payload_net_handler>::update_dns_blocklist, this));
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::update_dns_blocklist()
|
||||
{
|
||||
if (!m_enable_dns_blocklist)
|
||||
return true;
|
||||
if (m_nettype != cryptonote::MAINNET)
|
||||
return true;
|
||||
|
||||
static const std::vector<std::string> dns_urls = {
|
||||
"blocklist.moneropulse.se"
|
||||
, "blocklist.moneropulse.org"
|
||||
, "blocklist.moneropulse.net"
|
||||
, "blocklist.moneropulse.no"
|
||||
, "blocklist.moneropulse.fr"
|
||||
, "blocklist.moneropulse.de"
|
||||
, "blocklist.moneropulse.ch"
|
||||
};
|
||||
|
||||
std::vector<std::string> records;
|
||||
if (!tools::dns_utils::load_txt_records_from_dns(records, dns_urls))
|
||||
return true;
|
||||
|
||||
unsigned good = 0, bad = 0;
|
||||
for (const auto& record : records)
|
||||
{
|
||||
std::vector<std::string> ips;
|
||||
boost::split(ips, record, boost::is_any_of(";"));
|
||||
for (const auto &ip: ips)
|
||||
{
|
||||
if (ip.empty())
|
||||
continue;
|
||||
auto subnet = net::get_ipv4_subnet_address(ip);
|
||||
if (subnet)
|
||||
{
|
||||
block_subnet(*subnet, DNS_BLOCKLIST_LIFETIME);
|
||||
++good;
|
||||
continue;
|
||||
}
|
||||
const expect<epee::net_utils::network_address> parsed_addr = net::get_network_address(ip, 0);
|
||||
if (parsed_addr)
|
||||
{
|
||||
block_host(*parsed_addr, DNS_BLOCKLIST_LIFETIME, true);
|
||||
++good;
|
||||
continue;
|
||||
}
|
||||
MWARNING("Invalid IP address or subnet from DNS blocklist: " << ip << " - " << parsed_addr.error());
|
||||
++bad;
|
||||
}
|
||||
}
|
||||
if (good > 0)
|
||||
MINFO(good << " addresses added to the blocklist");
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
@@ -2093,7 +2171,10 @@ namespace nodetool
|
||||
|
||||
LOG_DEBUG_CC(context, "REMOTE PEERLIST: remote peerlist size=" << peerlist_.size());
|
||||
LOG_TRACE_CC(context, "REMOTE PEERLIST: " << ENDL << print_peerlist_to_string(peerlist_));
|
||||
return m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.merge_peerlist(peerlist_, [this](const peerlist_entry &pe) { return !is_addr_recently_failed(pe.adr); });
|
||||
CRITICAL_REGION_LOCAL(m_blocked_hosts_lock);
|
||||
return m_network_zones.at(context.m_remote_address.get_zone()).m_peerlist.merge_peerlist(peerlist_, [this](const peerlist_entry &pe) {
|
||||
return !is_addr_recently_failed(pe.adr) && is_remote_host_allowed(pe.adr);
|
||||
});
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
template<class t_payload_net_handler>
|
||||
@@ -2838,8 +2919,8 @@ namespace nodetool
|
||||
const uint32_t index = stripe - 1;
|
||||
CRITICAL_REGION_LOCAL(m_used_stripe_peers_mutex);
|
||||
MINFO("adding stripe " << stripe << " peer: " << context.m_remote_address.str());
|
||||
std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
|
||||
[&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; });
|
||||
m_used_stripe_peers[index].erase(std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
|
||||
[&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; }), m_used_stripe_peers[index].end());
|
||||
m_used_stripe_peers[index].push_back(context.m_remote_address);
|
||||
}
|
||||
|
||||
@@ -2852,8 +2933,8 @@ namespace nodetool
|
||||
const uint32_t index = stripe - 1;
|
||||
CRITICAL_REGION_LOCAL(m_used_stripe_peers_mutex);
|
||||
MINFO("removing stripe " << stripe << " peer: " << context.m_remote_address.str());
|
||||
std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
|
||||
[&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; });
|
||||
m_used_stripe_peers[index].erase(std::remove_if(m_used_stripe_peers[index].begin(), m_used_stripe_peers[index].end(),
|
||||
[&context](const epee::net_utils::network_address &na){ return context.m_remote_address == na; }), m_used_stripe_peers[index].end());
|
||||
}
|
||||
|
||||
template<class t_payload_net_handler>
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace nodetool
|
||||
virtual uint64_t get_public_connections_count()=0;
|
||||
virtual void for_each_connection(std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
|
||||
virtual bool for_connection(const boost::uuids::uuid&, std::function<bool(t_connection_context&, peerid_type, uint32_t)> f)=0;
|
||||
virtual bool block_host(epee::net_utils::network_address address, time_t seconds = 0)=0;
|
||||
virtual bool block_host(epee::net_utils::network_address address, time_t seconds = 0, bool add_only = false)=0;
|
||||
virtual bool unblock_host(const epee::net_utils::network_address &address)=0;
|
||||
virtual std::map<std::string, time_t> get_blocked_hosts()=0;
|
||||
virtual std::map<epee::net_utils::ipv4_network_subnet, time_t> get_blocked_subnets()=0;
|
||||
@@ -108,7 +108,7 @@ namespace nodetool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool block_host(epee::net_utils::network_address address, time_t seconds)
|
||||
virtual bool block_host(epee::net_utils::network_address address, time_t seconds, bool add_only)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -826,7 +826,7 @@ bool bulletproof_VERIFY(const std::vector<const Bulletproof*> &proofs)
|
||||
proof_data.reserve(proofs.size());
|
||||
size_t inv_offset = 0;
|
||||
std::vector<rct::key> to_invert;
|
||||
to_invert.reserve(11 * sizeof(proofs));
|
||||
to_invert.reserve(11 * proofs.size());
|
||||
size_t max_logM = 0;
|
||||
for (const Bulletproof *p: proofs)
|
||||
{
|
||||
|
||||
@@ -190,6 +190,7 @@ namespace cryptonote
|
||||
|
||||
request.gray = true;
|
||||
request.white = true;
|
||||
request.include_blocked = false;
|
||||
if (!on_get_public_nodes(request, response) || response.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
return {};
|
||||
@@ -498,6 +499,8 @@ namespace cryptonote
|
||||
res.database_size = round_up(res.database_size, 5ull* 1024 * 1024 * 1024);
|
||||
res.update_available = restricted ? false : m_core.is_update_available();
|
||||
res.version = restricted ? "" : MONERO_VERSION_FULL;
|
||||
res.busy_syncing = m_p2p.get_payload_object().is_busy_syncing();
|
||||
res.synchronized = check_core_ready();
|
||||
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
@@ -562,12 +565,12 @@ namespace cryptonote
|
||||
}
|
||||
}
|
||||
|
||||
size_t max_blocks = COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT;
|
||||
size_t max_blocks = COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT;
|
||||
if (m_rpc_payment)
|
||||
{
|
||||
max_blocks = res.credits / COST_PER_BLOCK;
|
||||
if (max_blocks > COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT)
|
||||
max_blocks = COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT;
|
||||
if (max_blocks > COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT)
|
||||
max_blocks = COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT;
|
||||
if (max_blocks == 0)
|
||||
{
|
||||
res.status = CORE_RPC_STATUS_PAYMENT_REQUIRED;
|
||||
@@ -576,7 +579,7 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::pair<cryptonote::blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, cryptonote::blobdata> > > > bs;
|
||||
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, req.prune, !req.no_miner_tx, max_blocks))
|
||||
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, bs, res.current_height, res.start_height, req.prune, !req.no_miner_tx, max_blocks, COMMAND_RPC_GET_BLOCKS_FAST_MAX_TX_COUNT))
|
||||
{
|
||||
res.status = "Failed";
|
||||
add_host_fail(ctx);
|
||||
@@ -1381,6 +1384,8 @@ namespace cryptonote
|
||||
|
||||
for (auto & entry : white_list)
|
||||
{
|
||||
if (!req.include_blocked && m_p2p.is_host_blocked(entry.adr, NULL))
|
||||
continue;
|
||||
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
|
||||
res.white_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(),
|
||||
entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash);
|
||||
@@ -1393,6 +1398,8 @@ namespace cryptonote
|
||||
|
||||
for (auto & entry : gray_list)
|
||||
{
|
||||
if (!req.include_blocked && m_p2p.is_host_blocked(entry.adr, NULL))
|
||||
continue;
|
||||
if (entry.adr.get_type_id() == epee::net_utils::ipv4_network_address::get_type_id())
|
||||
res.gray_list.emplace_back(entry.id, entry.adr.as<epee::net_utils::ipv4_network_address>().ip(),
|
||||
entry.adr.as<epee::net_utils::ipv4_network_address>().port(), entry.last_seen, entry.pruning_seed, entry.rpc_port, entry.rpc_credits_per_hash);
|
||||
@@ -1411,8 +1418,10 @@ namespace cryptonote
|
||||
{
|
||||
RPC_TRACKER(get_public_nodes);
|
||||
|
||||
COMMAND_RPC_GET_PEER_LIST::request peer_list_req;
|
||||
COMMAND_RPC_GET_PEER_LIST::response peer_list_res;
|
||||
const bool success = on_get_peer_list(COMMAND_RPC_GET_PEER_LIST::request(), peer_list_res, ctx);
|
||||
peer_list_req.include_blocked = req.include_blocked;
|
||||
const bool success = on_get_peer_list(peer_list_req, peer_list_res, ctx);
|
||||
res.status = peer_list_res.status;
|
||||
if (!success)
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace cryptonote
|
||||
// advance which version they will stop working with
|
||||
// Don't go over 32767 for any of these
|
||||
#define CORE_RPC_VERSION_MAJOR 3
|
||||
#define CORE_RPC_VERSION_MINOR 2
|
||||
#define CORE_RPC_VERSION_MINOR 5
|
||||
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
|
||||
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
|
||||
|
||||
@@ -684,7 +684,9 @@ namespace cryptonote
|
||||
bool was_bootstrap_ever_used;
|
||||
uint64_t database_size;
|
||||
bool update_available;
|
||||
bool busy_syncing;
|
||||
std::string version;
|
||||
bool synchronized;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_PARENT(rpc_access_response_base)
|
||||
@@ -723,7 +725,9 @@ namespace cryptonote
|
||||
KV_SERIALIZE(was_bootstrap_ever_used)
|
||||
KV_SERIALIZE(database_size)
|
||||
KV_SERIALIZE(update_available)
|
||||
KV_SERIALIZE(busy_syncing)
|
||||
KV_SERIALIZE(version)
|
||||
KV_SERIALIZE(synchronized)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<response_t> response;
|
||||
@@ -1191,10 +1195,12 @@ namespace cryptonote
|
||||
struct request_t: public rpc_request_base
|
||||
{
|
||||
bool public_only;
|
||||
bool include_blocked;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_PARENT(rpc_request_base)
|
||||
KV_SERIALIZE_OPT(public_only, true)
|
||||
KV_SERIALIZE_OPT(include_blocked, false)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
@@ -1240,11 +1246,13 @@ namespace cryptonote
|
||||
{
|
||||
bool gray;
|
||||
bool white;
|
||||
bool include_blocked;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE_PARENT(rpc_request_base)
|
||||
KV_SERIALIZE_OPT(gray, false)
|
||||
KV_SERIALIZE_OPT(white, true)
|
||||
KV_SERIALIZE_OPT(include_blocked, false)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
typedef epee::misc_utils::struct_init<request_t> request;
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace rpc
|
||||
{
|
||||
std::vector<std::pair<std::pair<blobdata, crypto::hash>, std::vector<std::pair<crypto::hash, blobdata> > > > blocks;
|
||||
|
||||
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, blocks, res.current_height, res.start_height, req.prune, true, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
|
||||
if(!m_core.find_blockchain_supplement(req.start_height, req.block_ids, blocks, res.current_height, res.start_height, req.prune, true, COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT, COMMAND_RPC_GET_BLOCKS_FAST_MAX_TX_COUNT))
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "core::find_blockchain_supplement() returned false";
|
||||
|
||||
@@ -98,7 +98,7 @@ template <>
|
||||
struct binary_archive<false> : public binary_archive_base<std::istream, false>
|
||||
{
|
||||
|
||||
explicit binary_archive(stream_type &s) : base_type(s) {
|
||||
explicit binary_archive(stream_type &s) : base_type(s), varint_bug_backward_compatibility_(false) {
|
||||
stream_type::pos_type pos = stream_.tellg();
|
||||
stream_.seekg(0, std::ios_base::end);
|
||||
eof_pos_ = stream_.tellg();
|
||||
@@ -173,8 +173,13 @@ struct binary_archive<false> : public binary_archive_base<std::istream, false>
|
||||
assert(stream_.tellg() <= eof_pos_);
|
||||
return eof_pos_ - stream_.tellg();
|
||||
}
|
||||
|
||||
void enable_varint_bug_backward_compatibility() { varint_bug_backward_compatibility_ = true; }
|
||||
bool varint_bug_backward_compatibility_enabled() const { return varint_bug_backward_compatibility_; }
|
||||
|
||||
protected:
|
||||
std::streamoff eof_pos_;
|
||||
bool varint_bug_backward_compatibility_;
|
||||
};
|
||||
|
||||
template <>
|
||||
@@ -227,6 +232,8 @@ struct binary_archive<true> : public binary_archive_base<std::ostream, true>
|
||||
void write_variant_tag(variant_tag_type t) {
|
||||
serialize_int(t);
|
||||
}
|
||||
|
||||
bool varint_bug_backward_compatibility_enabled() const { return false; }
|
||||
};
|
||||
|
||||
POP_WARNINGS
|
||||
|
||||
@@ -32,22 +32,27 @@ namespace serialization
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
inline constexpr bool use_container_varint() noexcept
|
||||
{
|
||||
return std::is_integral<T>::value && std::is_unsigned<T>::value && sizeof(T) > 1;
|
||||
}
|
||||
|
||||
template <typename Archive, class T>
|
||||
bool serialize_container_element(Archive& ar, T& e)
|
||||
typename std::enable_if<!use_container_varint<T>(), bool>::type
|
||||
serialize_container_element(Archive& ar, T& e)
|
||||
{
|
||||
return ::do_serialize(ar, e);
|
||||
}
|
||||
|
||||
template <typename Archive>
|
||||
bool serialize_container_element(Archive& ar, uint32_t& e)
|
||||
template<typename Archive, typename T>
|
||||
typename std::enable_if<use_container_varint<T>(), bool>::type
|
||||
serialize_container_element(Archive& ar, T& e)
|
||||
{
|
||||
ar.serialize_varint(e);
|
||||
return true;
|
||||
}
|
||||
static constexpr const bool previously_varint = std::is_same<uint64_t, T>() || std::is_same<uint32_t, T>();
|
||||
|
||||
template <typename Archive>
|
||||
bool serialize_container_element(Archive& ar, uint64_t& e)
|
||||
{
|
||||
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
|
||||
return ::do_serialize(ar, e);
|
||||
ar.serialize_varint(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ struct json_archive_base
|
||||
void end_variant() { end_object(); }
|
||||
Stream &stream() { return stream_; }
|
||||
|
||||
bool varint_bug_backward_compatibility_enabled() const { return false; }
|
||||
|
||||
protected:
|
||||
void make_indent()
|
||||
{
|
||||
|
||||
@@ -30,21 +30,34 @@
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
#include "serialization.h"
|
||||
|
||||
namespace serialization
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
inline constexpr bool use_pair_varint() noexcept
|
||||
{
|
||||
return std::is_integral<T>::value && std::is_unsigned<T>::value && sizeof(T) > 1;
|
||||
}
|
||||
|
||||
template <typename Archive, class T>
|
||||
bool serialize_pair_element(Archive& ar, T& e)
|
||||
typename std::enable_if<!use_pair_varint<T>(), bool>::type
|
||||
serialize_pair_element(Archive& ar, T& e)
|
||||
{
|
||||
return ::do_serialize(ar, e);
|
||||
}
|
||||
|
||||
template <typename Archive>
|
||||
bool serialize_pair_element(Archive& ar, uint64_t& e)
|
||||
template<typename Archive, typename T>
|
||||
typename std::enable_if<use_pair_varint<T>(), bool>::type
|
||||
serialize_pair_element(Archive& ar, T& e)
|
||||
{
|
||||
static constexpr const bool previously_varint = std::is_same<uint64_t, T>();
|
||||
|
||||
if (!previously_varint && ar.varint_bug_backward_compatibility_enabled() && !typename Archive::is_saving())
|
||||
return ::do_serialize(ar, e);
|
||||
ar.serialize_varint(e);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace
|
||||
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
|
||||
|
||||
const char* USAGE_START_MINING("start_mining [<number_of_threads>] [bg_mining] [ignore_battery]");
|
||||
const char* USAGE_SET_DAEMON("set_daemon <host>[:<port>] [trusted|untrusted]");
|
||||
const char* USAGE_SET_DAEMON("set_daemon <host>[:<port>] [trusted|untrusted|this-is-probably-a-spy-node]");
|
||||
const char* USAGE_SHOW_BALANCE("balance [detail]");
|
||||
const char* USAGE_INCOMING_TRANSFERS("incoming_transfers [available|unavailable] [verbose] [uses] [index=<N1>[,<N2>[,...]]]");
|
||||
const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
|
||||
@@ -2286,6 +2286,7 @@ bool simple_wallet::public_nodes(const std::vector<std::string> &args)
|
||||
{
|
||||
fail_msg_writer() << tr("Error retrieving public node list: ") << e.what();
|
||||
}
|
||||
message_writer(console_color_red, true) << tr("Most of these nodes are probably spies. You should not use them unless connecting via Tor or I2P");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3222,7 +3223,7 @@ simple_wallet::simple_wallet()
|
||||
m_cmd_binder.set_handler("set_daemon",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::set_daemon, _1),
|
||||
tr(USAGE_SET_DAEMON),
|
||||
tr("Set another daemon to connect to."));
|
||||
tr("Set another daemon to connect to. If it's not yours, it'll probably spy on you."));
|
||||
m_cmd_binder.set_handler("save_bc",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::save_bc, _1),
|
||||
tr("Save the current blockchain data."));
|
||||
@@ -5507,21 +5508,51 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
|
||||
} else {
|
||||
daemon_url = args[0];
|
||||
}
|
||||
LOCK_IDLE_SCOPE();
|
||||
m_wallet->init(daemon_url);
|
||||
|
||||
epee::net_utils::http::url_content parsed{};
|
||||
const bool r = epee::net_utils::parse_url(daemon_url, parsed);
|
||||
if (!r)
|
||||
{
|
||||
fail_msg_writer() << tr("Failed to parse address");
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string trusted;
|
||||
if (args.size() == 2)
|
||||
{
|
||||
if (args[1] == "trusted")
|
||||
m_wallet->set_trusted_daemon(true);
|
||||
trusted = "trusted";
|
||||
else if (args[1] == "untrusted")
|
||||
m_wallet->set_trusted_daemon(false);
|
||||
trusted = "untrusted";
|
||||
else if (args[1] == "this-is-probably-a-spy-node")
|
||||
trusted = "this-is-probably-a-spy-node";
|
||||
else
|
||||
{
|
||||
fail_msg_writer() << tr("Expected trusted or untrusted, got ") << args[1] << ": assuming untrusted";
|
||||
m_wallet->set_trusted_daemon(false);
|
||||
fail_msg_writer() << tr("Expected trusted, untrusted or this-is-probably-a-spy-node got ") << args[1];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tools::is_privacy_preserving_network(parsed.host) && !tools::is_local_address(parsed.host))
|
||||
{
|
||||
if (trusted == "untrusted" || trusted == "")
|
||||
{
|
||||
fail_msg_writer() << tr("This is not Tor/I2P address, and is not a trusted daemon.");
|
||||
fail_msg_writer() << tr("Either use your own trusted node, connect via Tor or I2P, or pass this-is-probably-a-spy-node and be spied on.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parsed.schema != "https")
|
||||
message_writer(console_color_red) << tr("Warning: connecting to a non-local daemon without SSL, passive adversaries will be able to spy on you.");
|
||||
}
|
||||
|
||||
LOCK_IDLE_SCOPE();
|
||||
m_wallet->init(daemon_url);
|
||||
|
||||
if (!trusted.empty())
|
||||
{
|
||||
m_wallet->set_trusted_daemon(trusted == "trusted");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_wallet->set_trusted_daemon(false);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_MONERO_VERSION "0.17.1.7"
|
||||
#define DEF_MONERO_VERSION "0.17.2.0"
|
||||
#define DEF_MONERO_RELEASE_NAME "Oxygen Orion"
|
||||
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
|
||||
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@
|
||||
|
||||
+16
-5
@@ -5649,6 +5649,16 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
|
||||
if (::serialization::serialize(ar, *this))
|
||||
if (::serialization::check_stream_state(ar))
|
||||
loaded = true;
|
||||
if (!loaded)
|
||||
{
|
||||
std::stringstream iss;
|
||||
iss << cache_data;
|
||||
binary_archive<false> ar(iss);
|
||||
ar.enable_varint_bug_backward_compatibility();
|
||||
if (::serialization::serialize(ar, *this))
|
||||
if (::serialization::check_stream_state(ar))
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
catch(...) { }
|
||||
|
||||
@@ -12439,7 +12449,7 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
|
||||
bool wallet2::export_key_images(const std::string &filename, bool all) const
|
||||
{
|
||||
PERF_TIMER(export_key_images);
|
||||
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(all);
|
||||
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = export_key_images(all);
|
||||
std::string magic(KEY_IMAGE_EXPORT_FILE_MAGIC, strlen(KEY_IMAGE_EXPORT_FILE_MAGIC));
|
||||
const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address;
|
||||
const uint32_t offset = ski.first;
|
||||
@@ -12466,7 +12476,7 @@ bool wallet2::export_key_images(const std::string &filename, bool all) const
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images(bool all) const
|
||||
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> wallet2::export_key_images(bool all) const
|
||||
{
|
||||
PERF_TIMER(export_key_images_raw);
|
||||
std::vector<std::pair<crypto::key_image, crypto::signature>> ski;
|
||||
@@ -12963,7 +12973,7 @@ void wallet2::import_blockchain(const std::tuple<size_t, crypto::hash, std::vect
|
||||
m_last_block_reward = cryptonote::get_outs_money_amount(genesis.miner_tx);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs(bool all) const
|
||||
std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> wallet2::export_outputs(bool all) const
|
||||
{
|
||||
PERF_TIMER(export_outputs);
|
||||
std::vector<tools::wallet2::transfer_details> outs;
|
||||
@@ -13003,7 +13013,7 @@ std::string wallet2::export_outputs_to_str(bool all) const
|
||||
return magic + ciphertext;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
size_t wallet2::import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs)
|
||||
size_t wallet2::import_outputs(const std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> &outputs)
|
||||
{
|
||||
PERF_TIMER(import_outputs);
|
||||
|
||||
@@ -13109,7 +13119,7 @@ size_t wallet2::import_outputs_from_str(const std::string &outputs_st)
|
||||
try
|
||||
{
|
||||
std::string body(data, headerlen);
|
||||
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
|
||||
std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> outputs;
|
||||
try
|
||||
{
|
||||
std::stringstream iss;
|
||||
@@ -14159,6 +14169,7 @@ std::vector<cryptonote::public_node> wallet2::get_public_nodes(bool white_only)
|
||||
|
||||
req.white = true;
|
||||
req.gray = !white_only;
|
||||
req.include_blocked = false;
|
||||
|
||||
{
|
||||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
|
||||
@@ -327,7 +327,7 @@ private:
|
||||
uint64_t m_block_height;
|
||||
cryptonote::transaction_prefix m_tx;
|
||||
crypto::hash m_txid;
|
||||
size_t m_internal_output_index;
|
||||
uint64_t m_internal_output_index;
|
||||
uint64_t m_global_output_index;
|
||||
bool m_spent;
|
||||
bool m_frozen;
|
||||
@@ -338,7 +338,7 @@ private:
|
||||
bool m_rct;
|
||||
bool m_key_image_known;
|
||||
bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested
|
||||
size_t m_pk_index;
|
||||
uint64_t m_pk_index;
|
||||
cryptonote::subaddress_index m_subaddr_index;
|
||||
bool m_key_image_partial;
|
||||
std::vector<rct::key> m_multisig_k;
|
||||
@@ -1367,9 +1367,9 @@ private:
|
||||
bool verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const;
|
||||
|
||||
// Import/Export wallet data
|
||||
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> export_outputs(bool all = false) const;
|
||||
std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> export_outputs(bool all = false) const;
|
||||
std::string export_outputs_to_str(bool all = false) const;
|
||||
size_t import_outputs(const std::pair<size_t, std::vector<tools::wallet2::transfer_details>> &outputs);
|
||||
size_t import_outputs(const std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> &outputs);
|
||||
size_t import_outputs_from_str(const std::string &outputs_st);
|
||||
payment_container export_payments() const;
|
||||
void import_payments(const payment_container &payments);
|
||||
@@ -1377,7 +1377,7 @@ private:
|
||||
std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> export_blockchain() const;
|
||||
void import_blockchain(const std::tuple<size_t, crypto::hash, std::vector<crypto::hash>> &bc);
|
||||
bool export_key_images(const std::string &filename, bool all = false) const;
|
||||
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const;
|
||||
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> export_key_images(bool all = false) const;
|
||||
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, size_t offset, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
|
||||
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
|
||||
bool import_key_images(std::vector<crypto::key_image> key_images, size_t offset=0, boost::optional<std::unordered_set<size_t>> selected_transfers=boost::none);
|
||||
|
||||
@@ -2702,7 +2702,7 @@ namespace tools
|
||||
if (!m_wallet) return not_open(er);
|
||||
try
|
||||
{
|
||||
std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all);
|
||||
std::pair<uint64_t, std::vector<std::pair<crypto::key_image, crypto::signature>>> ski = m_wallet->export_key_images(req.all);
|
||||
res.offset = ski.first;
|
||||
res.signed_key_images.resize(ski.second.size());
|
||||
for (size_t n = 0; n < ski.second.size(); ++n)
|
||||
|
||||
@@ -245,12 +245,17 @@ bool tests::proxy_core::init(const boost::program_options::variables_map& /*vm*/
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tests::proxy_core::have_block(const crypto::hash& id) {
|
||||
bool tests::proxy_core::have_block_unlocked(const crypto::hash& id, int *where) {
|
||||
if (m_hash2blkidx.end() == m_hash2blkidx.find(id))
|
||||
return false;
|
||||
if (where) *where = HAVE_BLOCK_MAIN_CHAIN;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tests::proxy_core::have_block(const crypto::hash& id, int *where) {
|
||||
return have_block_unlocked(id, where);
|
||||
}
|
||||
|
||||
void tests::proxy_core::build_short_history(std::list<crypto::hash> &m_history, const crypto::hash &m_start) {
|
||||
m_history.push_front(get_block_hash(m_genesis));
|
||||
/*std::unordered_map<crypto::hash, tests::block_index>::const_iterator cit = m_hash2blkidx.find(m_lastblk);
|
||||
|
||||
@@ -74,7 +74,8 @@ namespace tests
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
bool deinit(){return true;}
|
||||
bool get_short_chain_history(std::list<crypto::hash>& ids);
|
||||
bool have_block(const crypto::hash& id);
|
||||
bool have_block(const crypto::hash& id, int *where = NULL);
|
||||
bool have_block_unlocked(const crypto::hash& id, int *where = NULL);
|
||||
void get_blockchain_top(uint64_t& height, crypto::hash& top_id);
|
||||
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed);
|
||||
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blobs, std::vector<cryptonote::tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed);
|
||||
@@ -112,5 +113,6 @@ namespace tests
|
||||
bool prune_blockchain(uint32_t pruning_seed) const { return true; }
|
||||
bool get_txpool_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) { return false; }
|
||||
bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const { return false; }
|
||||
crypto::hash get_block_id_by_height(uint64_t height) const { return crypto::null_hash; }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ END_INIT_SIMPLE_FUZZER()
|
||||
|
||||
BEGIN_SIMPLE_FUZZER()
|
||||
std::string s((const char*)buf, len);
|
||||
std::pair<size_t, std::vector<tools::wallet2::transfer_details>> outputs;
|
||||
std::pair<uint64_t, std::vector<tools::wallet2::transfer_details>> outputs;
|
||||
std::stringstream iss;
|
||||
iss << s;
|
||||
binary_archive<false> ar(iss);
|
||||
|
||||
@@ -52,6 +52,9 @@ namespace
|
||||
|
||||
struct test_levin_connection_context : public epee::net_utils::connection_context_base
|
||||
{
|
||||
static constexpr int handshake_command() noexcept { return 1001; }
|
||||
static constexpr bool handshake_complete() noexcept { return true; }
|
||||
size_t get_max_bytes(int command) const { return LEVIN_DEFAULT_MAX_PACKET_SIZE; }
|
||||
};
|
||||
|
||||
typedef epee::levin::async_protocol_handler_config<test_levin_connection_context> test_levin_protocol_handler_config;
|
||||
|
||||
@@ -48,6 +48,9 @@ namespace net_load_tests
|
||||
struct test_connection_context : epee::net_utils::connection_context_base
|
||||
{
|
||||
test_connection_context(): epee::net_utils::connection_context_base(boost::uuids::nil_uuid(), {}, false, false), m_closed(false) {}
|
||||
static constexpr int handshake_command() noexcept { return 1001; }
|
||||
static constexpr bool handshake_complete() noexcept { return true; }
|
||||
size_t get_max_bytes(int command) const { return LEVIN_DEFAULT_MAX_PACKET_SIZE; }
|
||||
volatile bool m_closed;
|
||||
};
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "include_base_utils.h"
|
||||
#include "string_tools.h"
|
||||
#include "net/abstract_tcp_server2.h"
|
||||
#include "net/levin_protocol_handler_async.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -132,3 +133,333 @@ TEST(boosted_tcp_server, worker_threads_are_exception_resistant)
|
||||
ASSERT_TRUE(srv.timed_wait_server_stop(5 * 1000));
|
||||
ASSERT_TRUE(srv.deinit_server());
|
||||
}
|
||||
|
||||
|
||||
TEST(test_epee_connection, test_lifetime)
|
||||
{
|
||||
struct context_t: epee::net_utils::connection_context_base {
|
||||
static constexpr size_t get_max_bytes(int) noexcept { return -1; }
|
||||
static constexpr int handshake_command() noexcept { return 1001; }
|
||||
static constexpr bool handshake_complete() noexcept { return true; }
|
||||
};
|
||||
|
||||
using functional_obj_t = std::function<void ()>;
|
||||
struct command_handler_t: epee::levin::levin_commands_handler<context_t> {
|
||||
size_t delay;
|
||||
functional_obj_t on_connection_close_f;
|
||||
command_handler_t(size_t delay = 0,
|
||||
functional_obj_t on_connection_close_f = nullptr
|
||||
):
|
||||
delay(delay),
|
||||
on_connection_close_f(on_connection_close_f)
|
||||
{}
|
||||
virtual int invoke(int, const epee::span<const uint8_t>, std::string&, context_t&) override { epee::misc_utils::sleep_no_w(delay); return {}; }
|
||||
virtual int notify(int, const epee::span<const uint8_t>, context_t&) override { return {}; }
|
||||
virtual void callback(context_t&) override {}
|
||||
virtual void on_connection_new(context_t&) override {}
|
||||
virtual void on_connection_close(context_t&) override {
|
||||
if (on_connection_close_f)
|
||||
on_connection_close_f();
|
||||
}
|
||||
virtual ~command_handler_t() override {}
|
||||
static void destroy(epee::levin::levin_commands_handler<context_t>* ptr) { delete ptr; }
|
||||
};
|
||||
|
||||
using handler_t = epee::levin::async_protocol_handler<context_t>;
|
||||
using connection_t = epee::net_utils::connection<handler_t>;
|
||||
using connection_ptr = boost::shared_ptr<connection_t>;
|
||||
using shared_state_t = typename connection_t::shared_state;
|
||||
using shared_state_ptr = std::shared_ptr<shared_state_t>;
|
||||
using shared_states_t = std::vector<shared_state_ptr>;
|
||||
using tag_t = boost::uuids::uuid;
|
||||
using tags_t = std::vector<tag_t>;
|
||||
using io_context_t = boost::asio::io_service;
|
||||
using endpoint_t = boost::asio::ip::tcp::endpoint;
|
||||
using work_t = boost::asio::io_service::work;
|
||||
using work_ptr = std::shared_ptr<work_t>;
|
||||
using workers_t = std::vector<std::thread>;
|
||||
using server_t = epee::net_utils::boosted_tcp_server<handler_t>;
|
||||
using lock_t = std::mutex;
|
||||
using lock_guard_t = std::lock_guard<lock_t>;
|
||||
using connection_weak_ptr = boost::weak_ptr<connection_t>;
|
||||
struct shared_conn_t {
|
||||
lock_t lock;
|
||||
connection_weak_ptr conn;
|
||||
};
|
||||
using shared_conn_ptr = std::shared_ptr<shared_conn_t>;
|
||||
|
||||
io_context_t io_context;
|
||||
work_ptr work(std::make_shared<work_t>(io_context));
|
||||
|
||||
workers_t workers;
|
||||
while (workers.size() < 4) {
|
||||
workers.emplace_back([&io_context]{
|
||||
io_context.run();
|
||||
});
|
||||
}
|
||||
|
||||
endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 5262);
|
||||
server_t server(epee::net_utils::e_connection_type_P2P);
|
||||
server.init_server(endpoint.port(),
|
||||
endpoint.address().to_string(),
|
||||
0,
|
||||
"",
|
||||
false,
|
||||
true,
|
||||
epee::net_utils::ssl_support_t::e_ssl_support_disabled
|
||||
);
|
||||
server.run_server(2, false);
|
||||
server.get_config_shared()->set_handler(new command_handler_t, &command_handler_t::destroy);
|
||||
|
||||
io_context.post([&io_context, &work, &endpoint, &server]{
|
||||
auto scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&work]{
|
||||
work.reset();
|
||||
});
|
||||
|
||||
shared_state_ptr shared_state(std::make_shared<shared_state_t>());
|
||||
shared_state->set_handler(new command_handler_t, &command_handler_t::destroy);
|
||||
|
||||
auto create_connection = [&io_context, &endpoint, &shared_state] {
|
||||
connection_ptr conn(new connection_t(io_context, shared_state, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
context_t context;
|
||||
conn->get_context(context);
|
||||
auto tag = context.m_connection_id;
|
||||
return tag;
|
||||
};
|
||||
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 0);
|
||||
auto tag = create_connection();
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 1);
|
||||
bool success = shared_state->for_connection(tag, [shared_state](context_t& context){
|
||||
shared_state->close(context.m_connection_id);
|
||||
context.m_remote_address.get_zone();
|
||||
return true;
|
||||
});
|
||||
ASSERT_TRUE(success);
|
||||
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 0);
|
||||
constexpr auto N = 8;
|
||||
tags_t tags(N);
|
||||
for(auto &t: tags)
|
||||
t = create_connection();
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == N);
|
||||
size_t index = 0;
|
||||
success = shared_state->foreach_connection([&index, shared_state, &tags, &create_connection](context_t& context){
|
||||
if (!index)
|
||||
for (const auto &t: tags)
|
||||
shared_state->close(t);
|
||||
|
||||
shared_state->close(context.m_connection_id);
|
||||
context.m_remote_address.get_zone();
|
||||
++index;
|
||||
|
||||
for(auto i = 0; i < N; ++i)
|
||||
create_connection();
|
||||
return true;
|
||||
});
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_TRUE(index == N);
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == N * N);
|
||||
|
||||
index = 0;
|
||||
success = shared_state->foreach_connection([&index, shared_state](context_t& context){
|
||||
shared_state->close(context.m_connection_id);
|
||||
context.m_remote_address.get_zone();
|
||||
++index;
|
||||
return true;
|
||||
});
|
||||
ASSERT_TRUE(success);
|
||||
ASSERT_TRUE(index == N * N);
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 0);
|
||||
|
||||
while (shared_state->sock_count);
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 0);
|
||||
constexpr auto DELAY = 30;
|
||||
constexpr auto TIMEOUT = 1;
|
||||
server.get_config_shared()->set_handler(new command_handler_t(DELAY), &command_handler_t::destroy);
|
||||
for (auto i = 0; i < N; ++i) {
|
||||
tag = create_connection();
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 1);
|
||||
success = shared_state->invoke_async(1, {}, tag, [](int, const epee::span<const uint8_t>, context_t&){}, TIMEOUT);
|
||||
ASSERT_TRUE(success);
|
||||
while (shared_state->sock_count == 1) {
|
||||
success = shared_state->foreach_connection([&shared_state, &tag](context_t&){
|
||||
return shared_state->request_callback(tag);
|
||||
});
|
||||
ASSERT_TRUE(success);
|
||||
}
|
||||
shared_state->close(tag);
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 0);
|
||||
}
|
||||
|
||||
while (shared_state->sock_count);
|
||||
constexpr auto ZERO_DELAY = 0;
|
||||
size_t counter = 0;
|
||||
shared_state->set_handler(new command_handler_t(ZERO_DELAY,
|
||||
[&counter]{
|
||||
ASSERT_TRUE(counter++ == 0);
|
||||
}
|
||||
),
|
||||
&command_handler_t::destroy
|
||||
);
|
||||
connection_ptr conn(new connection_t(io_context, shared_state, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 1);
|
||||
shared_state->del_out_connections(1);
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 0);
|
||||
conn.reset();
|
||||
|
||||
while (shared_state->sock_count);
|
||||
shared_conn_ptr shared_conn(std::make_shared<shared_conn_t>());
|
||||
shared_state->set_handler(new command_handler_t(ZERO_DELAY,
|
||||
[shared_state, shared_conn]{
|
||||
{
|
||||
connection_ptr conn;
|
||||
{
|
||||
lock_guard_t guard(shared_conn->lock);
|
||||
conn = std::move(shared_conn->conn.lock());
|
||||
}
|
||||
if (conn)
|
||||
conn->cancel();
|
||||
}
|
||||
const auto success = shared_state->foreach_connection([](context_t&){
|
||||
return true;
|
||||
});
|
||||
ASSERT_TRUE(success);
|
||||
}
|
||||
),
|
||||
&command_handler_t::destroy
|
||||
);
|
||||
for (auto i = 0; i < N; ++i) {
|
||||
{
|
||||
connection_ptr conn(new connection_t(io_context, shared_state, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
lock_guard_t guard(shared_conn->lock);
|
||||
shared_conn->conn = conn;
|
||||
}
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 1);
|
||||
shared_state->del_out_connections(1);
|
||||
ASSERT_TRUE(shared_state->get_connections_count() == 0);
|
||||
}
|
||||
|
||||
shared_states_t shared_states;
|
||||
while (shared_states.size() < 2) {
|
||||
shared_states.emplace_back(std::make_shared<shared_state_t>());
|
||||
shared_states.back()->set_handler(new command_handler_t(ZERO_DELAY,
|
||||
[&shared_states]{
|
||||
for (auto &s: shared_states) {
|
||||
auto success = s->foreach_connection([](context_t&){
|
||||
return true;
|
||||
});
|
||||
ASSERT_TRUE(success);
|
||||
}
|
||||
}
|
||||
),
|
||||
&command_handler_t::destroy
|
||||
);
|
||||
}
|
||||
workers_t workers;
|
||||
|
||||
for (auto &s: shared_states) {
|
||||
workers.emplace_back([&io_context, &s, &endpoint]{
|
||||
for (auto i = 0; i < N * N; ++i) {
|
||||
connection_ptr conn(new connection_t(io_context, s, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
io_context.post([conn]{
|
||||
conn->cancel();
|
||||
});
|
||||
conn.reset();
|
||||
s->del_out_connections(1);
|
||||
while (s->sock_count);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (;workers.size(); workers.pop_back())
|
||||
workers.back().join();
|
||||
|
||||
for (auto &s: shared_states) {
|
||||
workers.emplace_back([&io_context, &s, &endpoint]{
|
||||
for (auto i = 0; i < N * N; ++i) {
|
||||
connection_ptr conn(new connection_t(io_context, s, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
conn->cancel();
|
||||
while (conn.use_count() > 1);
|
||||
s->foreach_connection([&io_context, &s, &endpoint, &conn](context_t& context){
|
||||
conn.reset(new connection_t(io_context, s, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
conn->cancel();
|
||||
while (conn.use_count() > 1);
|
||||
conn.reset();
|
||||
return true;
|
||||
});
|
||||
while (s->sock_count);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (;workers.size(); workers.pop_back())
|
||||
workers.back().join();
|
||||
|
||||
for (auto &s: shared_states) {
|
||||
workers.emplace_back([&io_context, &s, &endpoint]{
|
||||
for (auto i = 0; i < N; ++i) {
|
||||
connection_ptr conn(new connection_t(io_context, s, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
context_t context;
|
||||
conn->get_context(context);
|
||||
auto tag = context.m_connection_id;
|
||||
conn->cancel();
|
||||
while (conn.use_count() > 1);
|
||||
s->for_connection(tag, [&io_context, &s, &endpoint, &conn](context_t& context){
|
||||
conn.reset(new connection_t(io_context, s, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
conn->cancel();
|
||||
while (conn.use_count() > 1);
|
||||
conn.reset();
|
||||
return true;
|
||||
});
|
||||
while (s->sock_count);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (;workers.size(); workers.pop_back())
|
||||
workers.back().join();
|
||||
|
||||
for (auto &s: shared_states) {
|
||||
workers.emplace_back([&io_context, &s, &endpoint]{
|
||||
for (auto i = 0; i < N; ++i) {
|
||||
connection_ptr conn(new connection_t(io_context, s, {}, {}));
|
||||
conn->socket().connect(endpoint);
|
||||
conn->start({}, {});
|
||||
context_t context;
|
||||
conn->get_context(context);
|
||||
auto tag = context.m_connection_id;
|
||||
io_context.post([conn]{
|
||||
conn->cancel();
|
||||
});
|
||||
conn.reset();
|
||||
s->close(tag);
|
||||
while (s->sock_count);
|
||||
}
|
||||
});
|
||||
}
|
||||
for (;workers.size(); workers.pop_back())
|
||||
workers.back().join();
|
||||
|
||||
});
|
||||
|
||||
for (auto& w: workers) {
|
||||
w.join();
|
||||
}
|
||||
server.send_stop_signal();
|
||||
server.timed_wait_server_stop(5 * 1000);
|
||||
server.deinit_server();
|
||||
}
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace
|
||||
{
|
||||
struct test_levin_connection_context : public epee::net_utils::connection_context_base
|
||||
{
|
||||
static constexpr int handshake_command() noexcept { return 1001; }
|
||||
static constexpr bool handshake_complete() noexcept { return true; }
|
||||
size_t get_max_bytes(int command) const { return LEVIN_DEFAULT_MAX_PACKET_SIZE; }
|
||||
};
|
||||
|
||||
typedef epee::levin::async_protocol_handler_config<test_levin_connection_context> test_levin_protocol_handler_config;
|
||||
@@ -194,6 +197,7 @@ namespace
|
||||
{
|
||||
m_handler_config.set_handler(m_pcommands_handler, [](epee::levin::levin_commands_handler<test_levin_connection_context> *handler) { delete handler; });
|
||||
m_handler_config.m_invoke_timeout = invoke_timeout;
|
||||
m_handler_config.m_initial_max_packet_size = max_packet_size;
|
||||
m_handler_config.m_max_packet_size = max_packet_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -972,6 +972,23 @@ TEST(ByteStream, Put)
|
||||
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
|
||||
}
|
||||
|
||||
TEST(ByteStream, PutN)
|
||||
{
|
||||
using boost::range::equal;
|
||||
using byte_span = epee::span<const std::uint8_t>;
|
||||
|
||||
std::vector<std::uint8_t> bytes;
|
||||
bytes.resize(1000, 'f');
|
||||
|
||||
epee::byte_stream stream;
|
||||
stream.put_n('f', 1000);
|
||||
|
||||
EXPECT_EQ(1000u, stream.size());
|
||||
EXPECT_LE(1000u, stream.capacity());
|
||||
EXPECT_EQ(stream.available(), stream.capacity() - stream.size());
|
||||
EXPECT_TRUE(equal(bytes, byte_span{stream.data(), stream.size()}));
|
||||
}
|
||||
|
||||
TEST(ByteStream, Reserve)
|
||||
{
|
||||
using boost::range::equal;
|
||||
|
||||
@@ -178,17 +178,17 @@ namespace
|
||||
{
|
||||
using base_type = epee::net_utils::connection_context_base;
|
||||
static_cast<base_type&>(context_) = base_type{random_generator(), {}, is_incoming, false};
|
||||
context_.m_state = cryptonote::cryptonote_connection_context::state_normal;
|
||||
handler_.after_init_connection();
|
||||
}
|
||||
|
||||
//\return Number of messages processed
|
||||
std::size_t process_send_queue()
|
||||
std::size_t process_send_queue(const bool valid = true)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
for ( ; !endpoint_.send_queue_.empty(); ++count, endpoint_.send_queue_.pop_front())
|
||||
{
|
||||
// invalid messages shoudn't be possible in this test;
|
||||
EXPECT_TRUE(handler_.handle_recv(endpoint_.send_queue_.front().data(), endpoint_.send_queue_.front().size()));
|
||||
EXPECT_EQ(valid, handler_.handle_recv(endpoint_.send_queue_.front().data(), endpoint_.send_queue_.front().size()));
|
||||
}
|
||||
return count;
|
||||
}
|
||||
@@ -238,6 +238,13 @@ namespace
|
||||
return {connection, std::move(request)};
|
||||
}
|
||||
|
||||
static received_message get_raw_message(std::deque<received_message>& queue)
|
||||
{
|
||||
received_message out{std::move(queue.front())};
|
||||
queue.pop_front();
|
||||
return out;
|
||||
}
|
||||
|
||||
virtual int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out, cryptonote::levin::detail::p2p_context& context) override final
|
||||
{
|
||||
buff_out.clear();
|
||||
@@ -294,6 +301,11 @@ namespace
|
||||
{
|
||||
return get_message<T>(notified_);
|
||||
}
|
||||
|
||||
received_message get_raw_notification()
|
||||
{
|
||||
return get_raw_message(notified_);
|
||||
}
|
||||
};
|
||||
|
||||
class levin_notify : public ::testing::Test
|
||||
@@ -322,6 +334,8 @@ namespace
|
||||
EXPECT_EQ(0u, events_.relayed_method_size());
|
||||
}
|
||||
|
||||
cryptonote::levin::connections& get_connections() noexcept { return *connections_; }
|
||||
|
||||
void add_connection(const bool is_incoming)
|
||||
{
|
||||
contexts_.emplace_back(io_service_, *connections_, random_generator_, is_incoming);
|
||||
@@ -2140,3 +2154,27 @@ TEST_F(levin_notify, noise_stem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(levin_notify, command_max_bytes)
|
||||
{
|
||||
static constexpr int ping_command = nodetool::COMMAND_PING::ID;
|
||||
|
||||
add_connection(true);
|
||||
|
||||
std::string bytes(4096, 'h');
|
||||
|
||||
EXPECT_EQ(1, get_connections().notify(ping_command, epee::strspan<std::uint8_t>(bytes), contexts_.front().get_id()));
|
||||
EXPECT_EQ(1u, contexts_.front().process_send_queue(true));
|
||||
EXPECT_EQ(1u, receiver_.notified_size());
|
||||
|
||||
const received_message msg = receiver_.get_raw_notification();
|
||||
EXPECT_EQ(ping_command, msg.command);
|
||||
EXPECT_EQ(contexts_.front().get_id(), msg.connection);
|
||||
EXPECT_EQ(bytes, msg.payload);
|
||||
|
||||
bytes.push_back('e');
|
||||
|
||||
EXPECT_EQ(1, get_connections().notify(ping_command, epee::strspan<std::uint8_t>(bytes), contexts_.front().get_id()));
|
||||
EXPECT_EQ(1u, contexts_.front().process_send_queue(false));
|
||||
EXPECT_EQ(0u, receiver_.notified_size());
|
||||
}
|
||||
|
||||
@@ -55,7 +55,8 @@ public:
|
||||
bool init(const boost::program_options::variables_map& vm) {return true ;}
|
||||
bool deinit(){return true;}
|
||||
bool get_short_chain_history(std::list<crypto::hash>& ids) const { return true; }
|
||||
bool have_block(const crypto::hash& id) const {return true;}
|
||||
bool have_block(const crypto::hash& id, int *where = NULL) const {return false;}
|
||||
bool have_block_unlocked(const crypto::hash& id, int *where = NULL) const {return false;}
|
||||
void get_blockchain_top(uint64_t& height, crypto::hash& top_id)const{height=0;top_id=crypto::null_hash;}
|
||||
bool handle_incoming_tx(const cryptonote::tx_blob_entry& tx_blob, cryptonote::tx_verification_context& tvc, cryptonote::relay_method tx_relay, bool relayed) { return true; }
|
||||
bool handle_incoming_txs(const std::vector<cryptonote::tx_blob_entry>& tx_blob, std::vector<cryptonote::tx_verification_context>& tvc, cryptonote::relay_method tx_relay, bool relayed) { return true; }
|
||||
@@ -93,6 +94,7 @@ public:
|
||||
bool has_block_weights(uint64_t height, uint64_t nblocks) const { return false; }
|
||||
bool get_txpool_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) { return false; }
|
||||
bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_unrelayed_txes = true) const { return false; }
|
||||
crypto::hash get_block_id_by_height(uint64_t height) const { return crypto::null_hash; }
|
||||
void stop() {}
|
||||
};
|
||||
|
||||
@@ -292,6 +294,18 @@ TEST(node_server, bind_same_p2p_port)
|
||||
boost::program_options::variables_map vm;
|
||||
boost::program_options::store(boost::program_options::parse_command_line(1, argv, desc_options), vm);
|
||||
|
||||
/*
|
||||
Reason for choosing '127.0.0.2' as the IP:
|
||||
|
||||
A TCP local socket address that has been bound is unavailable for some time after closing, unless the SO_REUSEADDR flag has been set.
|
||||
That's why connections with automatically assigned source port 48080/58080 from previous test blocks the next to bind acceptor
|
||||
so solution is to either set reuse_addr option for each socket in all tests
|
||||
or use ip different from localhost for acceptors in order to not interfere with automatically assigned source endpoints
|
||||
|
||||
Relevant part about REUSEADDR from man:
|
||||
https://www.man7.org/linux/man-pages/man7/ip.7.html
|
||||
*/
|
||||
vm.find(nodetool::arg_p2p_bind_ip.name)->second = boost::program_options::variable_value(std::string("127.0.0.2"), false);
|
||||
vm.find(nodetool::arg_p2p_bind_port.name)->second = boost::program_options::variable_value(std::string(port), false);
|
||||
|
||||
boost::program_options::notify(vm);
|
||||
@@ -309,5 +323,594 @@ TEST(node_server, bind_same_p2p_port)
|
||||
EXPECT_TRUE(init(new_node(), port_another));
|
||||
}
|
||||
|
||||
TEST(cryptonote_protocol_handler, race_condition)
|
||||
{
|
||||
struct contexts {
|
||||
using basic = epee::net_utils::connection_context_base;
|
||||
using cryptonote = cryptonote::cryptonote_connection_context;
|
||||
using p2p = nodetool::p2p_connection_context_t<cryptonote>;
|
||||
};
|
||||
using context_t = contexts::p2p;
|
||||
using handler_t = epee::levin::async_protocol_handler<context_t>;
|
||||
using connection_t = epee::net_utils::connection<handler_t>;
|
||||
using connection_ptr = boost::shared_ptr<connection_t>;
|
||||
using connections_t = std::vector<connection_ptr>;
|
||||
using shared_state_t = typename connection_t::shared_state;
|
||||
using shared_state_ptr = std::shared_ptr<shared_state_t>;
|
||||
using io_context_t = boost::asio::io_service;
|
||||
using event_t = epee::simple_event;
|
||||
using ec_t = boost::system::error_code;
|
||||
auto create_conn_pair = [](connection_ptr in, connection_ptr out) {
|
||||
using endpoint_t = boost::asio::ip::tcp::endpoint;
|
||||
using acceptor_t = boost::asio::ip::tcp::acceptor;
|
||||
io_context_t io_context;
|
||||
endpoint_t endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 5262);
|
||||
acceptor_t acceptor(io_context);
|
||||
ec_t ec;
|
||||
acceptor.open(endpoint.protocol(), ec);
|
||||
EXPECT_EQ(ec.value(), 0);
|
||||
acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
acceptor.bind(endpoint, ec);
|
||||
EXPECT_EQ(ec.value(), 0);
|
||||
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
|
||||
EXPECT_EQ(ec.value(), 0);
|
||||
out->socket().open(endpoint.protocol(), ec);
|
||||
EXPECT_EQ(ec.value(), 0);
|
||||
acceptor.async_accept(in->socket(), [](const ec_t &ec){});
|
||||
out->socket().async_connect(endpoint, [](const ec_t &ec){});
|
||||
io_context.run();
|
||||
acceptor.close(ec);
|
||||
EXPECT_EQ(ec.value(), 0);
|
||||
EXPECT_TRUE(in->start(true, true));
|
||||
EXPECT_TRUE(out->start(false, true));
|
||||
return std::make_pair<>(std::move(in), std::move(out));
|
||||
};
|
||||
auto get_conn_tag = [](connection_t &conn){
|
||||
context_t context;
|
||||
conn.get_context(context);
|
||||
return context.m_connection_id;
|
||||
};
|
||||
using work_t = boost::asio::io_service::work;
|
||||
using work_ptr = std::shared_ptr<work_t>;
|
||||
using workers_t = std::vector<std::thread>;
|
||||
using commands_handler_t = epee::levin::levin_commands_handler<context_t>;
|
||||
using p2p_endpoint_t = nodetool::i_p2p_endpoint<contexts::cryptonote>;
|
||||
using core_t = cryptonote::core;
|
||||
using core_ptr = std::unique_ptr<core_t>;
|
||||
using core_protocol_t = cryptonote::t_cryptonote_protocol_handler<core_t>;
|
||||
using core_protocol_ptr = std::shared_ptr<core_protocol_t>;
|
||||
using block_t = cryptonote::block;
|
||||
using diff_t = cryptonote::difficulty_type;
|
||||
using reward_t = uint64_t;
|
||||
using height_t = uint64_t;
|
||||
struct span {
|
||||
using blocks = epee::span<const block_t>;
|
||||
};
|
||||
auto get_block_template = [](
|
||||
core_t &core,
|
||||
block_t &block,
|
||||
diff_t &diff,
|
||||
reward_t &reward
|
||||
){
|
||||
auto &storage = core.get_blockchain_storage();
|
||||
const auto height = storage.get_current_blockchain_height();
|
||||
const auto hardfork = storage.get_current_hard_fork_version();
|
||||
block.major_version = hardfork;
|
||||
block.minor_version = storage.get_ideal_hard_fork_version();
|
||||
block.prev_id = storage.get_tail_id();
|
||||
auto &db = storage.get_db();
|
||||
block.timestamp = db.get_top_block_timestamp();
|
||||
block.nonce = 0xACAB;
|
||||
block.miner_tx.vin.clear();
|
||||
block.miner_tx.vout.clear();
|
||||
block.miner_tx.extra.clear();
|
||||
block.miner_tx.version = hardfork >= 4 ? 2 : 1;
|
||||
block.miner_tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
block.miner_tx.vin.push_back(cryptonote::txin_gen{height});
|
||||
cryptonote::add_tx_pub_key_to_extra(block.miner_tx, {});
|
||||
cryptonote::get_block_reward(
|
||||
db.get_block_weight(height - 1),
|
||||
{},
|
||||
db.get_block_already_generated_coins(height - 1),
|
||||
reward,
|
||||
hardfork
|
||||
);
|
||||
block.miner_tx.vout.push_back(cryptonote::tx_out{reward, cryptonote::txout_to_key{}});
|
||||
diff = storage.get_difficulty_for_next_block();
|
||||
};
|
||||
struct stat {
|
||||
struct chain {
|
||||
diff_t diff;
|
||||
reward_t reward;
|
||||
};
|
||||
};
|
||||
auto add_block = [](
|
||||
core_t &core,
|
||||
const block_t &block,
|
||||
const stat::chain &stat
|
||||
){
|
||||
core.get_blockchain_storage().get_db().batch_start({}, {});
|
||||
core.get_blockchain_storage().get_db().add_block(
|
||||
{block, cryptonote::block_to_blob(block)},
|
||||
cryptonote::get_transaction_weight(block.miner_tx),
|
||||
core.get_blockchain_storage().get_next_long_term_block_weight(
|
||||
cryptonote::get_transaction_weight(block.miner_tx)
|
||||
),
|
||||
stat.diff,
|
||||
stat.reward,
|
||||
{}
|
||||
);
|
||||
core.get_blockchain_storage().get_db().batch_stop();
|
||||
};
|
||||
struct messages {
|
||||
struct core {
|
||||
using sync = cryptonote::CORE_SYNC_DATA;
|
||||
};
|
||||
using handshake = nodetool::COMMAND_HANDSHAKE_T<core::sync>;
|
||||
};
|
||||
struct net_node_t: commands_handler_t, p2p_endpoint_t {
|
||||
using span_t = epee::span<const uint8_t>;
|
||||
using string_t = std::string;
|
||||
using zone_t = epee::net_utils::zone;
|
||||
using uuid_t = boost::uuids::uuid;
|
||||
using relay_t = cryptonote::relay_method;
|
||||
using blobs_t = std::vector<cryptonote::blobdata>;
|
||||
using id_t = nodetool::peerid_type;
|
||||
using callback_t = std::function<bool(contexts::cryptonote &, id_t, uint32_t)>;
|
||||
using address_t = epee::net_utils::network_address;
|
||||
using connections_t = std::vector<std::pair<zone_t, uuid_t>>;
|
||||
struct bans {
|
||||
using subnets = std::map<epee::net_utils::ipv4_network_subnet, time_t>;
|
||||
using hosts = std::map<std::string, time_t>;
|
||||
};
|
||||
shared_state_ptr shared_state;
|
||||
core_protocol_ptr core_protocol;
|
||||
virtual int invoke(int command, const span_t in, string_t &out, context_t &context) override {
|
||||
if (core_protocol) {
|
||||
if (command == messages::handshake::ID) {
|
||||
return epee::net_utils::buff_to_t_adapter<void, typename messages::handshake::request, typename messages::handshake::response>(
|
||||
command,
|
||||
in,
|
||||
out,
|
||||
[this](int command, typename messages::handshake::request &in, typename messages::handshake::response &out, context_t &context){
|
||||
core_protocol->process_payload_sync_data(in.payload_data, context, true);
|
||||
core_protocol->get_payload_sync_data(out.payload_data);
|
||||
return 1;
|
||||
},
|
||||
context
|
||||
);
|
||||
}
|
||||
bool handled;
|
||||
return core_protocol->handle_invoke_map(false, command, in, out, context, handled);
|
||||
}
|
||||
else
|
||||
return {};
|
||||
}
|
||||
virtual int notify(int command, const span_t in, context_t &context) override {
|
||||
if (core_protocol) {
|
||||
bool handled;
|
||||
string_t out;
|
||||
return core_protocol->handle_invoke_map(true, command, in, out, context, handled);
|
||||
}
|
||||
else
|
||||
return {};
|
||||
}
|
||||
virtual void callback(context_t &context) override {
|
||||
if (core_protocol)
|
||||
core_protocol->on_callback(context);
|
||||
}
|
||||
virtual void on_connection_new(context_t&) override {}
|
||||
virtual void on_connection_close(context_t &context) override {
|
||||
if (core_protocol)
|
||||
core_protocol->on_connection_close(context);
|
||||
}
|
||||
virtual ~net_node_t() override {}
|
||||
virtual bool add_host_fail(const address_t&, unsigned int = {}) override {
|
||||
return {};
|
||||
}
|
||||
virtual bool block_host(address_t address, time_t = {}, bool = {}) override {
|
||||
return {};
|
||||
}
|
||||
virtual bool drop_connection(const contexts::basic& context) override {
|
||||
if (shared_state)
|
||||
return shared_state->close(context.m_connection_id);
|
||||
else
|
||||
return {};
|
||||
}
|
||||
virtual bool for_connection(const uuid_t& uuid, callback_t f) override {
|
||||
if (shared_state)
|
||||
return shared_state->for_connection(uuid,[&f](context_t &context){
|
||||
return f(context, context.peer_id, context.support_flags);
|
||||
});
|
||||
else
|
||||
return {};
|
||||
}
|
||||
virtual bool invoke_command_to_peer(int command, const span_t in, string_t& out, const contexts::basic& context) override {
|
||||
if (shared_state)
|
||||
return shared_state->invoke(command, in, out, context.m_connection_id);
|
||||
else
|
||||
return {};
|
||||
}
|
||||
virtual bool invoke_notify_to_peer(int command, const span_t in, const contexts::basic& context) override {
|
||||
if (shared_state)
|
||||
return shared_state->notify(command, in, context.m_connection_id);
|
||||
else
|
||||
return {};
|
||||
}
|
||||
virtual bool relay_notify_to_list(int command, const span_t in, connections_t connections) override {
|
||||
if (shared_state) {
|
||||
for (auto &e: connections)
|
||||
shared_state->notify(command, in, e.second);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
virtual bool unblock_host(const address_t&) override {
|
||||
return {};
|
||||
}
|
||||
virtual zone_t send_txs(blobs_t, const zone_t, const uuid_t&, relay_t) override {
|
||||
return {};
|
||||
}
|
||||
virtual bans::subnets get_blocked_subnets() override {
|
||||
return {};
|
||||
}
|
||||
virtual bans::hosts get_blocked_hosts() override {
|
||||
return {};
|
||||
}
|
||||
virtual uint64_t get_public_connections_count() override {
|
||||
if (shared_state)
|
||||
return shared_state->get_connections_count();
|
||||
else
|
||||
return {};
|
||||
}
|
||||
virtual void add_used_stripe_peer(const contexts::cryptonote&) override {}
|
||||
virtual void clear_used_stripe_peers() override {}
|
||||
virtual void remove_used_stripe_peer(const contexts::cryptonote&) override {}
|
||||
virtual void for_each_connection(callback_t f) override {
|
||||
if (shared_state)
|
||||
shared_state->foreach_connection([&f](context_t &context){
|
||||
return f(context, context.peer_id, context.support_flags);
|
||||
});
|
||||
}
|
||||
virtual void request_callback(const contexts::basic &context) override {
|
||||
if (shared_state)
|
||||
shared_state->request_callback(context.m_connection_id);
|
||||
}
|
||||
};
|
||||
auto conduct_handshake = [get_conn_tag](net_node_t &net_node, connection_ptr conn){
|
||||
event_t handshaked;
|
||||
net_node.shared_state->for_connection(
|
||||
get_conn_tag(*conn),
|
||||
[&handshaked, &net_node](context_t &context){
|
||||
typename messages::handshake::request msg;
|
||||
net_node.core_protocol->get_payload_sync_data(msg.payload_data);
|
||||
epee::net_utils::async_invoke_remote_command2<typename messages::handshake::response>(
|
||||
context,
|
||||
messages::handshake::ID,
|
||||
msg,
|
||||
*net_node.shared_state,
|
||||
[&handshaked, &net_node](int code, const typename messages::handshake::response &msg, context_t &context){
|
||||
EXPECT_TRUE(code >= 0);
|
||||
net_node.core_protocol->process_payload_sync_data(msg.payload_data, context, true);
|
||||
handshaked.raise();
|
||||
},
|
||||
P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT
|
||||
);
|
||||
return true;
|
||||
}
|
||||
);
|
||||
handshaked.wait();
|
||||
};
|
||||
using path_t = boost::filesystem::path;
|
||||
auto create_dir = []{
|
||||
ec_t ec;
|
||||
path_t path = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path("daemon-%%%%%%%%%%%%%%%%", ec);
|
||||
if (ec)
|
||||
return path_t{};
|
||||
auto success = boost::filesystem::create_directory(path, ec);
|
||||
if (not ec && success)
|
||||
return path;
|
||||
return path_t{};
|
||||
};
|
||||
auto remove_tree = [](const path_t &path){
|
||||
ec_t ec;
|
||||
boost::filesystem::remove_all(path, ec);
|
||||
};
|
||||
using options_t = boost::program_options::variables_map;
|
||||
struct daemon_t {
|
||||
options_t options;
|
||||
core_ptr core;
|
||||
core_protocol_ptr core_protocol;
|
||||
net_node_t net_node;
|
||||
shared_state_ptr shared_state;
|
||||
connections_t conn;
|
||||
};
|
||||
struct daemons_t {
|
||||
daemon_t main;
|
||||
daemon_t alt;
|
||||
};
|
||||
using options_description_t = boost::program_options::options_description;
|
||||
|
||||
const auto dir = create_dir();
|
||||
ASSERT_TRUE(not dir.empty());
|
||||
|
||||
daemons_t daemon{
|
||||
{
|
||||
[&dir]{
|
||||
options_t options;
|
||||
boost::program_options::store(
|
||||
boost::program_options::command_line_parser({
|
||||
"--data-dir",
|
||||
(dir / "main").string(),
|
||||
"--disable-dns-checkpoints",
|
||||
"--check-updates=disabled",
|
||||
"--fixed-difficulty=1",
|
||||
"--block-sync-size=1",
|
||||
"--db-sync-mode=fastest:async:50000",
|
||||
}).options([]{
|
||||
options_description_t options_description{};
|
||||
cryptonote::core::init_options(options_description);
|
||||
return options_description;
|
||||
}()).run(),
|
||||
options
|
||||
);
|
||||
return options;
|
||||
}(),
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
},
|
||||
{
|
||||
[&dir]{
|
||||
options_t options;
|
||||
boost::program_options::store(
|
||||
boost::program_options::command_line_parser({
|
||||
"--data-dir",
|
||||
(dir / "alt").string(),
|
||||
"--disable-dns-checkpoints",
|
||||
"--check-updates=disabled",
|
||||
"--fixed-difficulty=1",
|
||||
"--block-sync-size=1",
|
||||
"--db-sync-mode=fastest:async:50000",
|
||||
}).options([]{
|
||||
options_description_t options_description{};
|
||||
cryptonote::core::init_options(options_description);
|
||||
return options_description;
|
||||
}()).run(),
|
||||
options
|
||||
);
|
||||
return options;
|
||||
}(),
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
{},
|
||||
},
|
||||
};
|
||||
|
||||
io_context_t io_context;
|
||||
work_ptr work = std::make_shared<work_t>(io_context);
|
||||
workers_t workers;
|
||||
while (workers.size() < 4) {
|
||||
workers.emplace_back([&io_context]{
|
||||
io_context.run();
|
||||
});
|
||||
}
|
||||
|
||||
connection_t::set_rate_up_limit(std::numeric_limits<int64_t>::max());
|
||||
connection_t::set_rate_down_limit(std::numeric_limits<int64_t>::max());
|
||||
|
||||
{
|
||||
daemon.main.core = core_ptr(new core_t(nullptr));
|
||||
daemon.main.core->init(daemon.main.options, nullptr, nullptr);
|
||||
daemon.main.net_node.core_protocol = daemon.main.core_protocol = core_protocol_ptr(new core_protocol_t(
|
||||
*daemon.main.core, &daemon.main.net_node, {}
|
||||
));
|
||||
daemon.main.core->set_cryptonote_protocol(daemon.main.core_protocol.get());
|
||||
daemon.main.core_protocol->init(daemon.main.options);
|
||||
daemon.main.net_node.shared_state = daemon.main.shared_state = std::make_shared<shared_state_t>();
|
||||
daemon.main.shared_state->set_handler(&daemon.main.net_node);
|
||||
daemon.alt.shared_state = std::make_shared<shared_state_t>();
|
||||
daemon.alt.shared_state->set_handler(&daemon.alt.net_node);
|
||||
|
||||
struct {
|
||||
event_t prepare;
|
||||
event_t check;
|
||||
event_t finish;
|
||||
} events;
|
||||
auto connections = create_conn_pair(
|
||||
connection_ptr(new connection_t(io_context, daemon.main.shared_state, {}, {})),
|
||||
connection_ptr(new connection_t(io_context, daemon.alt.shared_state, {}, {}))
|
||||
);
|
||||
{
|
||||
auto conn = connections.first;
|
||||
auto shared_state = daemon.main.shared_state;
|
||||
const auto tag = get_conn_tag(*conn);
|
||||
conn->strand_.post([tag, conn, shared_state, &events]{
|
||||
shared_state->for_connection(tag, [](context_t &context){
|
||||
context.m_expect_height = -1;
|
||||
context.m_expect_response = -1;
|
||||
context.m_last_request_time = boost::date_time::min_date_time;
|
||||
context.m_score = 0;
|
||||
context.m_state = contexts::cryptonote::state_synchronizing;
|
||||
return true;
|
||||
});
|
||||
events.prepare.raise();
|
||||
events.check.wait();
|
||||
shared_state->for_connection(tag, [](context_t &context){
|
||||
EXPECT_TRUE(context.m_expect_height == -1);
|
||||
EXPECT_TRUE(context.m_expect_response == -1);
|
||||
EXPECT_TRUE(context.m_last_request_time == boost::date_time::min_date_time);
|
||||
EXPECT_TRUE(context.m_score == 0);
|
||||
EXPECT_TRUE(context.m_state == contexts::cryptonote::state_synchronizing);
|
||||
return true;
|
||||
});
|
||||
events.finish.raise();
|
||||
});
|
||||
}
|
||||
events.prepare.wait();
|
||||
daemon.main.core_protocol->on_idle();
|
||||
events.check.raise();
|
||||
events.finish.wait();
|
||||
|
||||
connections.first->strand_.post([connections]{
|
||||
connections.first->cancel();
|
||||
});
|
||||
connections.second->strand_.post([connections]{
|
||||
connections.second->cancel();
|
||||
});
|
||||
connections.first.reset();
|
||||
connections.second.reset();
|
||||
while (daemon.main.shared_state->sock_count);
|
||||
while (daemon.alt.shared_state->sock_count);
|
||||
daemon.main.core_protocol->deinit();
|
||||
daemon.main.core->stop();
|
||||
daemon.main.core->deinit();
|
||||
daemon.main.net_node.shared_state.reset();
|
||||
daemon.main.shared_state.reset();
|
||||
daemon.main.core_protocol.reset();
|
||||
daemon.main.core.reset();
|
||||
daemon.alt.shared_state.reset();
|
||||
}
|
||||
|
||||
{
|
||||
daemon.main.core = core_ptr(new core_t(nullptr));
|
||||
daemon.main.core->init(daemon.main.options, nullptr, nullptr);
|
||||
daemon.main.net_node.core_protocol = daemon.main.core_protocol = core_protocol_ptr(new core_protocol_t(
|
||||
*daemon.main.core, &daemon.main.net_node, {}
|
||||
));
|
||||
daemon.main.core->set_cryptonote_protocol(daemon.main.core_protocol.get());
|
||||
daemon.main.core->set_checkpoints({});
|
||||
daemon.main.core_protocol->init(daemon.main.options);
|
||||
daemon.main.net_node.shared_state = daemon.main.shared_state = std::make_shared<shared_state_t>();
|
||||
daemon.main.shared_state->set_handler(&daemon.main.net_node);
|
||||
daemon.alt.core = core_ptr(new core_t(nullptr));
|
||||
daemon.alt.core->init(daemon.alt.options, nullptr, nullptr);
|
||||
daemon.alt.net_node.core_protocol = daemon.alt.core_protocol = core_protocol_ptr(new core_protocol_t(
|
||||
*daemon.alt.core, &daemon.alt.net_node, {}
|
||||
));
|
||||
daemon.alt.core->set_cryptonote_protocol(daemon.alt.core_protocol.get());
|
||||
daemon.alt.core->set_checkpoints({});
|
||||
daemon.alt.core_protocol->init(daemon.alt.options);
|
||||
daemon.alt.net_node.shared_state = daemon.alt.shared_state = std::make_shared<shared_state_t>();
|
||||
daemon.alt.shared_state->set_handler(&daemon.alt.net_node);
|
||||
|
||||
struct {
|
||||
io_context_t io_context;
|
||||
work_ptr work;
|
||||
workers_t workers;
|
||||
} check;
|
||||
check.work = std::make_shared<work_t>(check.io_context);
|
||||
check.workers.emplace_back([&check]{
|
||||
check.io_context.run();
|
||||
});
|
||||
while (daemon.main.conn.size() < 1) {
|
||||
daemon.main.conn.emplace_back(new connection_t(check.io_context, daemon.main.shared_state, {}, {}));
|
||||
daemon.alt.conn.emplace_back(new connection_t(io_context, daemon.alt.shared_state, {}, {}));
|
||||
create_conn_pair(daemon.main.conn.back(), daemon.alt.conn.back());
|
||||
conduct_handshake(daemon.alt.net_node, daemon.alt.conn.back());
|
||||
}
|
||||
struct {
|
||||
event_t prepare;
|
||||
event_t sync;
|
||||
event_t finish;
|
||||
} events;
|
||||
{
|
||||
auto conn = daemon.main.conn.back();
|
||||
auto shared_state = daemon.main.shared_state;
|
||||
const auto tag = get_conn_tag(*conn);
|
||||
conn->strand_.post([tag, conn, shared_state, &events]{
|
||||
shared_state->for_connection(tag, [](context_t &context){
|
||||
EXPECT_TRUE(context.m_state == contexts::cryptonote::state_normal);
|
||||
return true;
|
||||
});
|
||||
events.prepare.raise();
|
||||
events.sync.wait();
|
||||
shared_state->for_connection(tag, [](context_t &context){
|
||||
EXPECT_TRUE(context.m_state == contexts::cryptonote::state_normal);
|
||||
return true;
|
||||
});
|
||||
events.finish.raise();
|
||||
});
|
||||
}
|
||||
events.prepare.wait();
|
||||
daemon.main.core->get_blockchain_storage().add_block_notify(
|
||||
[&events](height_t height, span::blocks blocks){
|
||||
if (height >= CRYPTONOTE_PRUNING_STRIPE_SIZE)
|
||||
events.sync.raise();
|
||||
}
|
||||
);
|
||||
{
|
||||
stat::chain stat{
|
||||
daemon.alt.core->get_blockchain_storage().get_db().get_block_cumulative_difficulty(
|
||||
daemon.alt.core->get_current_blockchain_height() - 1
|
||||
),
|
||||
daemon.alt.core->get_blockchain_storage().get_db().get_block_already_generated_coins(
|
||||
daemon.alt.core->get_current_blockchain_height() - 1
|
||||
),
|
||||
};
|
||||
while (daemon.alt.core->get_current_blockchain_height() < CRYPTONOTE_PRUNING_STRIPE_SIZE + CRYPTONOTE_PRUNING_TIP_BLOCKS) {
|
||||
block_t block;
|
||||
diff_t diff;
|
||||
reward_t reward;
|
||||
get_block_template(*daemon.alt.core, block, diff, reward);
|
||||
stat.diff += diff;
|
||||
stat.reward = stat.reward < (MONEY_SUPPLY - stat.reward) ? stat.reward + reward : MONEY_SUPPLY;
|
||||
add_block(*daemon.alt.core, block, stat);
|
||||
if (daemon.main.core->get_current_blockchain_height() + 1 < CRYPTONOTE_PRUNING_STRIPE_SIZE)
|
||||
add_block(*daemon.main.core, block, stat);
|
||||
}
|
||||
}
|
||||
while (daemon.main.conn.size() < 2) {
|
||||
daemon.main.conn.emplace_back(new connection_t(io_context, daemon.main.shared_state, {}, {}));
|
||||
daemon.alt.conn.emplace_back(new connection_t(io_context, daemon.alt.shared_state, {}, {}));
|
||||
create_conn_pair(daemon.main.conn.back(), daemon.alt.conn.back());
|
||||
conduct_handshake(daemon.alt.net_node, daemon.alt.conn.back());
|
||||
}
|
||||
events.finish.wait();
|
||||
|
||||
for (;daemon.main.conn.size(); daemon.main.conn.pop_back()) {
|
||||
auto conn = daemon.main.conn.back();
|
||||
conn->strand_.post([conn]{
|
||||
conn->cancel();
|
||||
});
|
||||
}
|
||||
for (;daemon.alt.conn.size(); daemon.alt.conn.pop_back()) {
|
||||
auto conn = daemon.alt.conn.back();
|
||||
conn->strand_.post([conn]{
|
||||
conn->cancel();
|
||||
});
|
||||
}
|
||||
while (daemon.main.shared_state->sock_count);
|
||||
while (daemon.alt.shared_state->sock_count);
|
||||
daemon.main.core_protocol->deinit();
|
||||
daemon.main.core->stop();
|
||||
daemon.main.core->deinit();
|
||||
daemon.main.net_node.shared_state.reset();
|
||||
daemon.main.shared_state.reset();
|
||||
daemon.main.core_protocol.reset();
|
||||
daemon.main.core.reset();
|
||||
daemon.alt.core_protocol->deinit();
|
||||
daemon.alt.core->stop();
|
||||
daemon.alt.core->deinit();
|
||||
daemon.alt.net_node.shared_state.reset();
|
||||
daemon.alt.shared_state.reset();
|
||||
daemon.alt.core_protocol.reset();
|
||||
daemon.alt.core.reset();
|
||||
check.work.reset();
|
||||
for (auto& w: check.workers) {
|
||||
w.join();
|
||||
}
|
||||
}
|
||||
|
||||
work.reset();
|
||||
for (auto& w: workers) {
|
||||
w.join();
|
||||
}
|
||||
remove_tree(dir);
|
||||
}
|
||||
|
||||
namespace nodetool { template class node_server<cryptonote::t_cryptonote_protocol_handler<test_core>>; }
|
||||
namespace cryptonote { template class t_cryptonote_protocol_handler<test_core>; }
|
||||
|
||||
Reference in New Issue
Block a user