merge dev branch with RPC/wallet3 changes

Incomplete, many things to fix, some annotated with
a comment MERGEFIX
This commit is contained in:
Thomas Winget 2022-07-11 20:40:50 -04:00
commit 1311a20e9f
319 changed files with 9402 additions and 10508 deletions

View File

@ -6,7 +6,6 @@ local default_deps_nocxx = [
'libevent-dev',
'libgtest-dev',
'libhidapi-dev',
'libminiupnpc-dev',
'libreadline-dev',
'libsodium-dev',
'libsqlite3-dev',
@ -35,6 +34,7 @@ local submodules = {
local apt_get_quiet = 'apt-get -o=Dpkg::Use-Pty=0 -q';
local cmake_options(opts) = std.join(' ', [' -D' + o + '=' + (if opts[o] then 'ON' else 'OFF') for o in std.objectFields(opts)]) + ' ';
// Regular build on a debian-like system:
local debian_pipeline(name,
@ -74,15 +74,14 @@ local debian_pipeline(name,
'mkdir build',
'cd build',
'cmake .. -G Ninja -DCMAKE_CXX_FLAGS=-fdiagnostics-color=always -DCMAKE_BUILD_TYPE=' + build_type + ' ' +
'-DLOCAL_MIRROR=https://builds.lokinet.dev/deps -DUSE_LTO=' + (if lto then 'ON ' else 'OFF ') +
(if werror then '-DWARNINGS_AS_ERRORS=ON ' else '') +
(if build_tests || run_tests then '-DBUILD_TESTS=ON ' else '') +
cmake_extra,
'-DLOCAL_MIRROR=https://builds.lokinet.dev/deps '
+ cmake_options({ USE_LTO: lto, WARNINGS_AS_ERRORS: werror, BUILD_TESTS: build_tests || run_tests })
+ cmake_extra,
] + (
if arch == 'arm64' && jobs > 1 then
// The wallet code is too bloated to be compiled at -j2 with only 4GB ram, so do
// the huge bloated jobs at -j1 and the rest at -j2
['ninja -j1 rpc wallet -v', 'ninja -j2 daemon device_trezor -v', 'ninja -j1 wallet_rpc_server -v', 'ninja -j2 -v']
['ninja -j1 rpc wallet -v', 'ninja -j2 daemon -v', 'ninja -j1 wallet_rpc_server -v', 'ninja -j2 -v']
else
['ninja -j' + jobs + ' -v']
) + (
@ -178,7 +177,7 @@ local android_build_steps(android_abi, android_platform=21, jobs=6, cmake_extra=
'-DCMAKE_BUILD_TYPE=Release ' +
'-DCMAKE_TOOLCHAIN_FILE=/usr/lib/android-sdk/ndk-bundle/build/cmake/android.toolchain.cmake ' +
'-DANDROID_PLATFORM=' + android_platform + ' -DANDROID_ABI=' + android_abi + ' ' +
'-DMONERO_SLOW_HASH=ON ' +
cmake_options({ MONERO_SLOW_HASH: true, WARNINGS_AS_ERRORS: false, BUILD_TESTS: false }) +
'-DLOCAL_MIRROR=https://builds.lokinet.dev/deps ' +
'-DBUILD_STATIC_DEPS=ON -DSTATIC=ON -G Ninja ' + cmake_extra,
'ninja -j' + jobs + ' -v wallet_merged',
@ -327,13 +326,13 @@ local gui_wallet_step_darwin = {
'mkdir -p build/{arm64,sim64}',
'cd build/arm64',
'cmake ../.. -G Ninja ' +
'-DCMAKE_TOOLCHAIN_FILE=../../cmake/ios.toolchain.cmake -DPLATFORM=OS -DDEPLOYMENT_TARGET=11 -DENABLE_VISIBILITY=ON -DENABLE_BITCODE=OFF ' +
'-DCMAKE_TOOLCHAIN_FILE=../../cmake/ios.toolchain.cmake -DPLATFORM=OS -DDEPLOYMENT_TARGET=13 -DENABLE_VISIBILITY=ON -DENABLE_BITCODE=OFF ' +
'-DSTATIC=ON -DBUILD_STATIC_DEPS=ON -DUSE_LTO=OFF -DCMAKE_BUILD_TYPE=Release ' +
'-DRANDOMX_ENABLE_JIT=OFF -DCMAKE_CXX_FLAGS=-fcolor-diagnostics',
'ninja -j6 -v wallet_merged',
'cd ../sim64',
'cmake ../.. -G Ninja ' +
'-DCMAKE_TOOLCHAIN_FILE=../../cmake/ios.toolchain.cmake -DPLATFORM=SIMULATOR64 -DDEPLOYMENT_TARGET=11 -DENABLE_VISIBILITY=ON -DENABLE_BITCODE=OFF ' +
'-DCMAKE_TOOLCHAIN_FILE=../../cmake/ios.toolchain.cmake -DPLATFORM=SIMULATOR64 -DDEPLOYMENT_TARGET=13 -DENABLE_VISIBILITY=ON -DENABLE_BITCODE=OFF ' +
'-DSTATIC=ON -DBUILD_STATIC_DEPS=ON -DUSE_LTO=OFF -DCMAKE_BUILD_TYPE=Release ' +
'-DRANDOMX_ENABLE_JIT=OFF -DCMAKE_CXX_FLAGS=-fcolor-diagnostics',
'ninja -j6 -v wallet_merged',

11
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "external/miniupnp"]
path = external/miniupnp
url = https://github.com/miniupnp/miniupnp
[submodule "external/rapidjson"]
path = external/rapidjson
url = https://github.com/Tencent/rapidjson
@ -11,7 +8,7 @@
path = external/randomx
url = https://github.com/oxen-io/loki-randomXL
[submodule "external/loki-mq"]
path = external/loki-mq
path = external/oxen-mq
url = https://github.com/oxen-io/loki-mq.git
[submodule "external/googletest"]
path = external/googletest
@ -46,6 +43,6 @@
[submodule "external/fmt"]
path = external/fmt
url = https://github.com/fmtlib/fmt.git
[submodule "external/oxenc"]
path = external/oxenc
url = https://www.github.com/oxen-io/oxen-encoding.git
[submodule "external/oxen-encoding"]
path = external/oxen-encoding
url = https://github.com/oxen-io/oxen-encoding.git

View File

@ -51,9 +51,9 @@ message(STATUS "CMake version ${CMAKE_VERSION}")
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12 CACHE STRING "macOS deployment target (Apple clang only)")
project(oxen
VERSION 9.2.0
VERSION 10.1.0
LANGUAGES CXX C)
set(OXEN_RELEASE_CODENAME "Audacious Aurochs")
set(OXEN_RELEASE_CODENAME "Wistful Wagyu")
# String value to append to the full version string; this is intended to easily identify whether a
# binary was build from the release or development branches. This should be permanently set to an
@ -284,11 +284,11 @@ if(NOT MANUAL_SUBMODULES)
endfunction ()
message(STATUS "Checking submodules")
check_submodule(external/miniupnp)
check_submodule(external/rapidjson)
check_submodule(external/trezor-common)
check_submodule(external/randomx)
check_submodule(external/loki-mq cppzmq)
check_submodule(external/oxen-mq cppzmq)
check_submodule(external/SQLiteCpp)
if(BUILD_TESTS)
check_submodule(external/googletest)
check_submodule(external/Catch2)
@ -324,7 +324,6 @@ else()
endif()
message(STATUS "Building for a ${ARCH_WIDTH}-bit system")
# Check if we're on FreeBSD so we can exclude the local miniupnpc (it should be installed from ports instead)
# CMAKE_SYSTEM_NAME checks are commonly known, but specifically taken from libsdl's CMakeLists
if(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD.*|FreeBSD")
set(FREEBSD TRUE)
@ -431,24 +430,6 @@ find_package(Threads)
if (APPLE AND NOT IOS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default")
if (NOT OpenSSL_DIR)
EXECUTE_PROCESS(COMMAND brew --prefix openssl
OUTPUT_VARIABLE OPENSSL_ROOT_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Using OpenSSL found at ${OPENSSL_ROOT_DIR}")
endif()
endif()
if(BUILD_STATIC_DEPS)
# SSL::* targets already set up
else()
find_package(OpenSSL REQUIRED)
endif()
message(STATUS "Using OpenSSL include dir at ${OPENSSL_INCLUDE_DIR}")
if(MINGW)
# OpenSSL doesn't seem to properly set up its dependencies on Windows, leading to linking errors
target_link_libraries(OpenSSL::Crypto INTERFACE ws2_32)
endif()
add_definition_if_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
@ -458,7 +439,6 @@ add_definition_if_function_found(strptime HAVE_STRPTIME)
# Generate header for embedded translations
add_subdirectory(translations)
add_library(miniupnpc INTERFACE)
add_library(systemd INTERFACE) # Will do nothing unless we find and enable systemd support
if(NOT TARGET sodium)
@ -481,17 +461,10 @@ if(NOT TARGET sodium)
target_link_libraries(sodium INTERFACE sodium_vendor)
endif()
# Need this target export so that loki-mq properly picks up sodium
# Need this target export so that oxen-mq properly picks up sodium
export(TARGETS sodium NAMESPACE sodium:: FILE sodium-exports.cmake)
endif()
if (NOT BUILD_STATIC_DEPS)
find_package(PkgConfig REQUIRED)
pkg_check_modules(UNBOUND libunbound REQUIRED IMPORTED_TARGET)
add_library(libunbound INTERFACE)
target_link_libraries(libunbound INTERFACE PkgConfig::UNBOUND)
endif()
option(WITH_SYSTEMD "Attempts to link against and enable systemd daemon notification support" ON)
if (WITH_SYSTEMD AND NOT BUILD_STATIC_DEPS)
find_package(PkgConfig REQUIRED)
@ -507,6 +480,7 @@ endif()
if(NOT BUILD_STATIC_DEPS)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SQLITE3 REQUIRED sqlite3 IMPORTED_TARGET GLOBAL)
message(STATUS "Found sqlite3 ${SQLITE3_VERSION}")
add_library(SQLite::SQLite3 ALIAS PkgConfig::SQLITE3)
@ -797,7 +771,7 @@ set(Boost_USE_MULTITHREADED TRUE) # Needed for macOS, at least, and won't hurt e
if(BUILD_STATIC_DEPS)
# StaticBuild.cmake sets Boost targets up for us
else()
find_package(Boost 1.58 QUIET REQUIRED COMPONENTS system thread serialization program_options)
find_package(Boost 1.62 QUIET REQUIRED COMPONENTS system thread serialization program_options)
endif()
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES})
@ -805,12 +779,6 @@ if(NOT Boost_FOUND)
message(FATAL_ERROR "Could not find Boost libraries, please make sure you have installed Boost or libboost-all-dev (>=1.58) or the equivalent")
elseif(Boost_FOUND)
message(STATUS "Found Boost Version: ${Boost_VERSION}")
if (OPENSSL_VERSION VERSION_GREATER_EQUAL 1.1 AND (
Boost_VERSION VERSION_LESS 1.62.0 OR (Boost_VERSION VERSION_GREATER 100000 AND Boost_VERSION VERSION_LESS 106200)))
message(FATAL_ERROR "Boost ${Boost_VERSION} (older than 1.62) is too old to link with OpenSSL ${OPENSSL_VERSION} (1.1 or newer) found at ${OPENSSL_INCLUDE_DIR} and ${OPENSSL_LIBRARIES}. "
"Update Boost or install OpenSSL 1.0 and set path to it when running cmake: "
"cmake -DOPENSSL_ROOT_DIR='/usr/include/openssl-1.0'")
endif()
endif()
# Interface target for random extra system libraries that we need to link everything against

View File

@ -43,18 +43,14 @@ library archives (`.a`).
| CMake | 3.10 | NO | `cmake` | `cmake` | `cmake` | NO | |
| pkg-config | any | NO | `pkg-config` | `base-devel` | `pkgconf` | NO | |
| Boost | 1.65 | NO | `libboost-all-dev`[2] | `boost` | `boost-devel` | NO | C++ libraries |
| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `openssl-devel` | NO | sha256 sum |
| libzmq | 4.3.0 | YES | `libzmq3-dev` | `zeromq` | `zeromq-devel` | NO | ZeroMQ library |
| sqlite3 | ? | YES | `libsqlite3-dev` | `sqlite` | `sqlite-devel` | NO | Oxen Name System |
| libunbound | 1.4.16 | NO | `libunbound-dev` | `unbound` | `unbound-devel` | NO | DNS resolver |
| libsodium | 1.0.9 | YES | `libsodium-dev` | `libsodium` | `libsodium-devel` | NO | cryptography |
| libcurl | 4.0 | NO | `libcurl4-openssl-dev` | `curl` | `curl-devel` | NO | HTTP RPC |
| libcurl | 4.0 | NO | `libcurl4-dev` | `curl` | `curl-devel` | NO | HTTP RPC |
| libuv (Win) | any | NO | (Windows only) | -- | -- | NO | RPC event loop |
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | YES | Stack traces |
| liblzma | any | NO | `liblzma-dev` | `xz` | `xz-devel` | YES | For libunwind |
| libreadline | 6.3.0 | NO | `libreadline-dev` | `readline` | `readline-devel` | YES | Input editing |
| ldns | 1.6.17 | NO | `libldns-dev` | `ldns` | `ldns-devel` | YES | SSL toolkit |
| expat | 1.1 | NO | `libexpat1-dev` | `expat` | `expat-devel` | YES | XML parsing |
| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | YES | Documentation |
| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | YES | Documentation |
| Qt tools | 5.x | NO | `qttools5-dev` | `qt5-tools` | `qt5-linguist` | YES | Translations |
@ -73,14 +69,14 @@ breakdown of the minimum set of required boost packages.
Install all dependencies at once on Debian/Ubuntu:
```
sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libldns-dev libexpat1-dev doxygen graphviz libpgm-dev libsqlite3-dev libcurl4-openssl-dev
sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libzmq3-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev doxygen graphviz libpgm-dev libsqlite3-dev libcurl4-dev
```
Install all dependencies at once on macOS with the provided Brewfile:
``` brew update && brew bundle --file=contrib/brew/Brewfile ```
FreeBSD one liner for required to build dependencies
```pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium sqlite3 openssl unbound miniupnpc```
```pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium sqlite3```
### Build instructions
@ -190,13 +186,13 @@ application.
To build for 64-bit Windows:
```bash
pacman -S git mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-sqlite3 mingw-w64-x86_64-unbound
pacman -S git mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-sqlite3
```
To build for 32-bit Windows:
```bash
pacman -S git mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi mingw-w64-i686-sqlite3 mingw-w64-i686-unbound
pacman -S git mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi mingw-w64-i686-sqlite3
```
* Close and reopen the MSYS MinGW shell via `MSYS2 MinGW 64-bit` shortcut on
@ -403,54 +399,6 @@ oxen-wallet-cli, and possibly oxend, if you get crashes refreshing.
See [README.i18n.md](README.i18n.md).
## Using Tor
> There is a new, still experimental, [integration with Tor](ANONYMITY_NETWORKS.md). The
> feature allows connecting over IPv4 and Tor simulatenously - IPv4 is used for
> relaying blocks and relaying transactions received by peers whereas Tor is
> used solely for relaying transactions received over local RPC. This provides
> privacy and better protection against surrounding node (sybil) attacks.
While Oxen isn't made to integrate with Tor, it can be used wrapped with torsocks, by
setting the following configuration parameters and environment variables:
* `--p2p-bind-ip 127.0.0.1` on the command line or `p2p-bind-ip=127.0.0.1` in
oxend.conf to disable listening for connections on external interfaces.
* `--no-igd` on the command line or `no-igd=1` in oxend.conf to disable IGD
(UPnP port forwarding negotiation), which is pointless with Tor.
* `DNS_PUBLIC=tcp` or `DNS_PUBLIC=tcp://x.x.x.x` where x.x.x.x is the IP of the
desired DNS server, for DNS requests to go over TCP, so that they are routed
through Tor. When IP is not specified, oxend uses the default list of
servers defined in [src/common/dns_utils.cpp](src/common/dns_utils.cpp).
* `TORSOCKS_ALLOW_INBOUND=1` to tell torsocks to allow oxend to bind to interfaces
to accept connections from the wallet. On some Linux systems, torsocks
allows binding to localhost by default, so setting this variable is only
necessary to allow binding to local LAN/VPN interfaces to allow wallets to
connect from remote hosts. On other systems, it may be needed for local wallets
as well.
* Do NOT pass `--detach` when running through torsocks with systemd, (see
[utils/systemd/oxend.service](utils/systemd/oxend.service) for details).
* If you use the wallet with a Tor daemon via the loopback IP (eg, 127.0.0.1:9050),
then use `--untrusted-daemon` unless it is your own hidden service.
Example command line to start oxend through Tor:
```bash
DNS_PUBLIC=tcp torsocks oxend --p2p-bind-ip 127.0.0.1 --no-igd
```
### Using Tor on Tails
TAILS ships with a very restrictive set of firewall rules. Therefore, you need
to add a rule to allow this connection too, in addition to telling torsocks to
allow inbound connections. Full example:
```bash
sudo iptables -I OUTPUT 2 -p tcp -d 127.0.0.1 -m tcp --dport 22023 -j ACCEPT
DNS_PUBLIC=tcp torsocks ./oxend --p2p-bind-ip 127.0.0.1 --no-igd --rpc-bind-ip 127.0.0.1 \
--data-dir /home/amnesia/Persistent/your/directory/to/the/blockchain
```
## Debugging
This section contains general instructions for debugging failed installs or problems encountered with Oxen. First ensure you are running the latest version built from the Github repo.

View File

@ -1,4 +1,5 @@
# Copyright (c) 2014-2018, The Monero Project
# Copyright (c) 2019-2022, The Oxen Project
#
# All rights reserved.
#
@ -33,32 +34,27 @@ execute_process(COMMAND "${GIT}" rev-parse --short=9 HEAD RESULT_VARIABLE RET OU
if(RET)
# Something went wrong, set the version tag to -unknown
message(WARNING "Cannot determine current commit. Make sure that you are building either from a Git working tree or from a source archive.")
set(VERSIONTAG "unknown")
configure_file("version.cpp.in" "version.cpp")
else()
string(SUBSTRING ${COMMIT} 0 9 COMMIT)
message(STATUS "You are currently on commit ${COMMIT}")
# Get all the tags
execute_process(COMMAND "${GIT}" rev-list --tags --max-count=1 --abbrev-commit RESULT_VARIABLE RET OUTPUT_VARIABLE TAGGEDCOMMIT OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT TAGGEDCOMMIT)
message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.")
set(VERSIONTAG "${COMMIT}")
else()
message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}")
# Check if we're building that tagged commit or a different one
if(COMMIT STREQUAL TAGGEDCOMMIT)
message(STATUS "You are building a tagged release")
message(STATUS "${COMMIT} is a tagged release; setting version tag to 'release'")
set(VERSIONTAG "release")
else()
message(STATUS "You are ahead of or behind a tagged release")
message(STATUS "You are not building a tagged release; setting version tag to '${COMMIT}'")
set(VERSIONTAG "${COMMIT}")
endif()
endif()
configure_file("version.cpp.in" "version.cpp")
endif()
endif()
configure_file("${SRC}" "${DEST}" @ONLY)

View File

@ -5,39 +5,19 @@
set(LOCAL_MIRROR "" CACHE STRING "local mirror path/URL for lib downloads")
set(OPENSSL_VERSION 1.1.1k CACHE STRING "openssl version")
set(OPENSSL_MIRROR ${LOCAL_MIRROR} https://www.openssl.org/source CACHE STRING "openssl download mirror(s)")
set(OPENSSL_SOURCE openssl-${OPENSSL_VERSION}.tar.gz)
set(OPENSSL_HASH SHA256=892a0875b9872acd04a9fde79b1f943075d5ea162415de3047c327df33fbaee5
CACHE STRING "openssl source hash")
set(EXPAT_VERSION 2.3.0 CACHE STRING "expat version")
string(REPLACE "." "_" EXPAT_TAG "R_${EXPAT_VERSION}")
set(EXPAT_MIRROR ${LOCAL_MIRROR} https://github.com/libexpat/libexpat/releases/download/${EXPAT_TAG}
CACHE STRING "expat download mirror(s)")
set(EXPAT_SOURCE expat-${EXPAT_VERSION}.tar.xz)
set(EXPAT_HASH SHA512=dde8a9a094b18d795a0e86ca4aa68488b352dc67019e0d669e8b910ed149628de4c2a49bc3a5b832f624319336a01f9e4debe03433a43e1c420f36356d886820
CACHE STRING "expat source hash")
set(UNBOUND_VERSION 1.13.1 CACHE STRING "unbound version")
set(UNBOUND_MIRROR ${LOCAL_MIRROR} https://nlnetlabs.nl/downloads/unbound CACHE STRING "unbound download mirror(s)")
set(UNBOUND_SOURCE unbound-${UNBOUND_VERSION}.tar.gz)
set(UNBOUND_HASH SHA256=8504d97b8fc5bd897345c95d116e0ee0ddf8c8ff99590ab2b4bd13278c9f50b8
CACHE STRING "unbound source hash")
set(BOOST_VERSION 1.76.0 CACHE STRING "boost version")
set(BOOST_VERSION 1.79.0 CACHE STRING "boost version")
set(BOOST_MIRROR ${LOCAL_MIRROR} https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION}/source
CACHE STRING "boost download mirror(s)")
string(REPLACE "." "_" BOOST_VERSION_ ${BOOST_VERSION})
set(BOOST_SOURCE boost_${BOOST_VERSION_}.tar.bz2)
set(BOOST_HASH SHA256=f0397ba6e982c4450f27bf32a2a83292aba035b827a5623a14636ea583318c41
set(BOOST_HASH SHA256=475d589d51a7f8b3ba2ba4eda022b170e562ca3b760ee922c146b6c65856ef39
CACHE STRING "boost source hash")
set(NCURSES_VERSION 6.2 CACHE STRING "ncurses version")
set(NCURSES_VERSION 6.3 CACHE STRING "ncurses version")
set(NCURSES_MIRROR ${LOCAL_MIRROR} http://ftpmirror.gnu.org/gnu/ncurses
CACHE STRING "ncurses download mirror(s)")
set(NCURSES_SOURCE ncurses-${NCURSES_VERSION}.tar.gz)
set(NCURSES_HASH SHA512=4c1333dcc30e858e8a9525d4b9aefb60000cfc727bc4a1062bace06ffc4639ad9f6e54f6bdda0e3a0e5ea14de995f96b52b3327d9ec633608792c99a1e8d840d
set(NCURSES_HASH SHA512=5373f228cba6b7869210384a607a2d7faecfcbfef6dbfcd7c513f4e84fbd8bcad53ac7db2e7e84b95582248c1039dcfc7c4db205a618f7da22a166db482f0105
CACHE STRING "ncurses source hash")
set(READLINE_VERSION 8.1 CACHE STRING "readline version")
@ -47,11 +27,11 @@ set(READLINE_SOURCE readline-${READLINE_VERSION}.tar.gz)
set(READLINE_HASH SHA512=27790d0461da3093a7fee6e89a51dcab5dc61928ec42e9228ab36493b17220641d5e481ea3d8fee5ee0044c70bf960f55c7d3f1a704cf6b9c42e5c269b797e00
CACHE STRING "readline source hash")
set(SQLITE3_VERSION 3350500 CACHE STRING "sqlite3 version")
set(SQLITE3_MIRROR ${LOCAL_MIRROR} https://www.sqlite.org/2021
set(SQLITE3_VERSION 3380200 CACHE STRING "sqlite3 version")
set(SQLITE3_MIRROR ${LOCAL_MIRROR} https://www.sqlite.org/2022
CACHE STRING "sqlite3 download mirror(s)")
set(SQLITE3_SOURCE sqlite-autoconf-${SQLITE3_VERSION}.tar.gz)
set(SQLITE3_HASH SHA512=039af796f79fc4517be0bd5ba37886264d49da309e234ae6fccdb488ef0109ed2b917fc3e6c1fc7224dff4f736824c653aaf8f0a37550c5ebc14d035cb8ac737
set(SQLITE3_HASH SHA512=2192675d8638a933ec75ec78dc4185f005c9d37453bc2bbe590b72235066f68ba2cac1be3b491a47d6a7ca74d5b3bfe4e548d576a6b324383bb9bc7739d0b635
CACHE STRING "sqlite3 source hash")
if(SQLITE3_VERSION MATCHES "^([0-9]+)(0([0-9])|([1-9][0-9]))(0([0-9])|([1-9][0-9]))[0-9][0-9]$")
@ -63,25 +43,25 @@ else()
endif()
set(EUDEV_VERSION 3.2.10 CACHE STRING "eudev version")
set(EUDEV_MIRROR ${LOCAL_MIRROR} https://github.com/gentoo/eudev/archive/
set(EUDEV_VERSION 3.2.11 CACHE STRING "eudev version")
set(EUDEV_MIRROR ${LOCAL_MIRROR} https://github.com/eudev-project/eudev/archive/
CACHE STRING "eudev download mirror(s)")
set(EUDEV_SOURCE v${EUDEV_VERSION}.tar.gz)
set(EUDEV_HASH SHA512=37fc5e7f960a843fa68269697882123af4515555788a9e856474f51dd8c330a4c8e52e7c897aeb5d3eb36c6ad66cc99f5a38a284a75620b7e6c275c703e25d42
set(EUDEV_HASH SHA512=17b328365913af3e434abe667dd0498c3702a41c6cb66f3793ca2c195b05ac06397b0a401077f81df7dd25193e4eeea13657a221ca6cb3d237c4d91e31e30b33
CACHE STRING "eudev source hash")
set(LIBUSB_VERSION 1.0.24 CACHE STRING "libusb version")
set(LIBUSB_VERSION 1.0.26 CACHE STRING "libusb version")
set(LIBUSB_MIRROR ${LOCAL_MIRROR} https://github.com/libusb/libusb/releases/download/v${LIBUSB_VERSION}
CACHE STRING "libusb download mirror(s)")
set(LIBUSB_SOURCE libusb-${LIBUSB_VERSION}.tar.bz2)
set(LIBUSB_HASH SHA512=5aea36a530aaa15c6dd656d0ed3ce204522c9946d8d39ffbb290dab4a98cda388a2598da4995123d1032324056090bd429e702459626d3e8d7daeebc4e7ff3dc
set(LIBUSB_HASH SHA512=fcdb85c98f21639668693c2fd522814d440972d65883984c4ae53d0555bdbdb7e8c7a32199cd4b01113556a1eb5be7841b750cc73c9f6bda79bfe1af80914e71
CACHE STRING "libusb source hash")
set(HIDAPI_VERSION 0.9.0 CACHE STRING "hidapi version")
set(HIDAPI_VERSION 0.11.2 CACHE STRING "hidapi version")
set(HIDAPI_MIRROR ${LOCAL_MIRROR} https://github.com/libusb/hidapi/archive
CACHE STRING "hidapi download mirror(s)")
set(HIDAPI_SOURCE hidapi-${HIDAPI_VERSION}.tar.gz)
set(HIDAPI_HASH SHA512=d9f28d394b78daece7d2dfb946e62349a56b388b3a06241585c6fad5a4e24dc914723de6c0f12a9e51cd23fb245f6b5ac9b3721319646d5ba5912bbe0a3f9a52
set(HIDAPI_HASH SHA512=c4d04bf570aa98dd88d7ce08ef1abb0675d500c9aa2c22f0437fa30b700a94446779f77e1170267926d5f6f0d9cdb2bb81ad1fe20d158c18587fddbca59e9517
CACHE STRING "hidapi source hash")
# NB: not currently built, used for (non-functional) trezor code
@ -108,18 +88,18 @@ set(ZMQ_SOURCE zeromq-${ZMQ_VERSION}.tar.gz)
set(ZMQ_HASH SHA512=e198ef9f82d392754caadd547537666d4fba0afd7d027749b3adae450516bcf284d241d4616cad3cb4ad9af8c10373d456de92dc6d115b037941659f141e7c0e
CACHE STRING "libzmq source hash")
set(ZLIB_VERSION 1.2.11 CACHE STRING "zlib version")
set(ZLIB_VERSION 1.2.12 CACHE STRING "zlib version")
set(ZLIB_MIRROR ${LOCAL_MIRROR} https://zlib.net
CACHE STRING "zlib mirror(s)")
set(ZLIB_SOURCE zlib-${ZLIB_VERSION}.tar.gz)
set(ZLIB_HASH SHA512=73fd3fff4adeccd4894084c15ddac89890cd10ef105dd5e1835e1e9bbb6a49ff229713bd197d203edfa17c2727700fce65a2a235f07568212d820dca88b528ae
set(ZLIB_HASH SHA512=cc2366fa45d5dfee1f983c8c51515e0cff959b61471e2e8d24350dea22d3f6fcc50723615a911b046ffc95f51ba337d39ae402131a55e6d1541d3b095d6c0a14
CACHE STRING "zlib source hash")
set(CURL_VERSION 7.76.1 CACHE STRING "curl version")
set(CURL_MIRROR ${LOCAL_MIRROR} https://curl.haxx.se/download https://curl.askapache.com
set(CURL_VERSION 7.82.0 CACHE STRING "curl version")
set(CURL_MIRROR ${LOCAL_MIRROR} https://curl.se/download https://curl.askapache.com
CACHE STRING "curl mirror(s)")
set(CURL_SOURCE curl-${CURL_VERSION}.tar.xz)
set(CURL_HASH SHA256=64bb5288c39f0840c07d077e30d9052e1cbb9fa6c2dc52523824cc859e679145
set(CURL_HASH SHA256=0aaa12d7bd04b0966254f2703ce80dd5c38dbbd76af0297d3d690cdce58a583c
CACHE STRING "curl source hash")
@ -141,16 +121,12 @@ if (ANDROID)
endif()
if(CMAKE_ANDROID_ARCH_ABI MATCHES x86_64)
set(android_clang x86_64-linux-android${ANDROID_PLATFORM_LEVEL}-clang)
set(openssl_machine x86_64)
elseif(CMAKE_ANDROID_ARCH_ABI MATCHES x86)
set(android_clang i686-linux-android${ANDROID_PLATFORM_LEVEL}-clang)
set(openssl_machine i686)
elseif(CMAKE_ANDROID_ARCH_ABI MATCHES armeabi-v7a)
set(android_clang armv7a-linux-androideabi${ANDROID_PLATFORM_LEVEL}-clang)
set(openssl_machine armv7)
elseif(CMAKE_ANDROID_ARCH_ABI MATCHES arm64-v8a)
set(android_clang aarch64-linux-android${ANDROID_PLATFORM_LEVEL}-clang)
set(openssl_machine aarch64)
else()
message(FATAL_ERROR "Don't know how to build for android arch abi ${CMAKE_ANDROID_ARCH_ABI}")
endif()
@ -276,74 +252,6 @@ add_static_target(zlib zlib_external libz.a)
set(openssl_configure ./config)
set(openssl_system_env "")
set(openssl_cc "${deps_cc}")
if(CMAKE_CROSSCOMPILING)
if(ARCH_TRIPLET STREQUAL x86_64-w64-mingw32)
set(openssl_system_env SYSTEM=MINGW64 RC=${CMAKE_RC_COMPILER})
elseif(ARCH_TRIPLET STREQUAL i686-w64-mingw32)
set(openssl_system_env SYSTEM=MINGW64 RC=${CMAKE_RC_COMPILER})
elseif(ANDROID)
set(openssl_system_env SYSTEM=Linux MACHINE=${openssl_machine} ${cross_extra})
set(openssl_extra_opts no-asm)
elseif(IOS)
get_filename_component(apple_toolchain "${CMAKE_C_COMPILER}" DIRECTORY)
get_filename_component(apple_sdk "${CMAKE_OSX_SYSROOT}" NAME)
if(NOT ${apple_toolchain} MATCHES Xcode OR NOT ${apple_sdk} MATCHES "iPhone(OS|Simulator)")
message(FATAL_ERROR "didn't find your toolchain and sdk correctly from ${CMAKE_C_COMPILER}/${CMAKE_OSX_SYSROOT}: found toolchain=${apple_toolchain}, sdk=${apple_sdk}")
endif()
set(openssl_system_env CROSS_COMPILE=${apple_toolchain}/ CROSS_TOP=${CMAKE_DEVELOPER_ROOT} CROSS_SDK=${apple_sdk})
set(openssl_configure ./Configure iphoneos-cross)
set(openssl_cc "clang")
endif()
endif()
build_external(openssl
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env CC=${openssl_cc} ${openssl_system_env} ${openssl_configure}
--prefix=${DEPS_DESTDIR} ${openssl_extra_opts} no-shared no-capieng no-dso no-dtls1 no-ec_nistp_64_gcc_128 no-gost
no-heartbeats no-md2 no-rc5 no-rdrand no-rfc3779 no-sctp no-ssl-trace no-ssl2 no-ssl3
no-static-engine no-tests no-weak-ssl-ciphers no-zlib-dynamic "CFLAGS=${deps_CFLAGS}"
INSTALL_COMMAND make install_sw
BUILD_BYPRODUCTS
${DEPS_DESTDIR}/lib/libssl.a ${DEPS_DESTDIR}/lib/libcrypto.a
${DEPS_DESTDIR}/include/openssl/ssl.h ${DEPS_DESTDIR}/include/openssl/crypto.h
)
add_static_target(OpenSSL::SSL openssl_external libssl.a)
add_static_target(OpenSSL::Crypto openssl_external libcrypto.a)
set(OPENSSL_INCLUDE_DIR ${DEPS_DESTDIR}/include)
set(OPENSSL_VERSION 1.1.1)
build_external(expat
CONFIGURE_COMMAND ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --enable-static
--disable-shared --with-pic --without-examples --without-tests --without-docbook --without-xmlwf
"CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}"
)
add_static_target(expat expat_external libexpat.a)
set(unbound_extra)
if(APPLE AND IOS)
# I have no idea why this is necessary: without this it runs `clang -E` which should work, but
# doesn't because... hurray ios is wonderful?
set(unbound_extra CPP=cpp)
endif()
build_external(unbound
DEPENDS openssl_external expat_external
CONFIGURE_COMMAND ./configure ${cross_host} ${cross_extra} --prefix=${DEPS_DESTDIR} --disable-shared
--enable-static --with-libunbound-only --with-pic --disable-gost
--$<IF:$<BOOL:${USE_LTO}>,enable,disable>-flto --with-ssl=${DEPS_DESTDIR}
--with-libexpat=${DEPS_DESTDIR}
"CC=${deps_cc}" "CFLAGS=${deps_CFLAGS}" ${unbound_extra}
)
add_static_target(libunbound unbound_external libunbound.a)
if(WIN32)
set_target_properties(libunbound PROPERTIES INTERFACE_LINK_LIBRARIES "ws2_32;crypt32;iphlpapi")
endif()
set(boost_threadapi "pthread")
set(boost_bootstrap_cxx "--cxx=${deps_cxx}")
set(boost_toolset "")
@ -526,14 +434,21 @@ else()
set(hidapi_libusb_lib libhidapi.a)
set(hidapi_lib_byproducts ${DEPS_DESTDIR}/lib/libhidapi.a)
endif()
set(hidapi_cmake_toolchain)
if(CMAKE_TOOLCHAIN_FILE)
set(hidapi_cmake_toolchain "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}")
endif()
build_external(hidapi
DEPENDS ${maybe_eudev} libusb_external
PATCH_COMMAND patch -p1 -i ${PROJECT_SOURCE_DIR}/utils/build_scripts/hidapi-autoconf-duplicate-macro-dir.patch
CONFIGURE_COMMAND autoreconf -ivf && ./configure ${cross_host} --prefix=${DEPS_DESTDIR} --disable-shared --enable-static --with-pic
"CC=${deps_cc}" "CXX=${deps_cxx}" "CFLAGS=${deps_CFLAGS}" "CXXFLAGS=${deps_CXXFLAGS}"
${cross_extra}
"libudev_CFLAGS=-I${DEPS_DESTDIR}/include" "libudev_LIBS=-L${DEPS_DESTDIR}/lib -ludev"
"libusb_CFLAGS=-I${DEPS_DESTDIR}/include/libusb-1.0" "libusb_LIBS=-L${DEPS_DESTDIR}/lib -lusb-1.0"
CONFIGURE_COMMAND mkdir -p build && cd build && cmake .. "-DCMAKE_GENERATOR=Unix Makefiles"
"-DCMAKE_PREFIX_PATH=${DEPS_DESTDIR}" "-DCMAKE_INSTALL_PREFIX=${DEPS_DESTDIR}"
"-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}"
"-DCMAKE_C_COMPILER_LAUNCHER=${CMAKE_C_COMPILER_LAUNCHER}"
"-DCMAKE_C_FLAGS=${deps_CFLAGS}"
${hidapi_cmake_toolchain}
-DBUILD_SHARED_LIBS=OFF
BUILD_COMMAND cd build && make
INSTALL_COMMAND cd build && make install
BUILD_BYPRODUCTS
${hidapi_lib_byproducts}
${DEPS_DESTDIR}/include/hidapi
@ -544,6 +459,8 @@ else()
set(hidapi_links "libusb_vendor;libudev")
if(WIN32)
list(APPEND hidapi_links setupapi)
elseif(APPLE)
list(APPEND hidapi_links "-framework AppKit")
endif()
set_target_properties(hidapi_libusb PROPERTIES
INTERFACE_LINK_LIBRARIES "${hidapi_links}"
@ -595,6 +512,7 @@ build_external(zmq
${zmq_patch}
CONFIGURE_COMMAND ./configure ${zmq_cross_host} --prefix=${DEPS_DESTDIR} --enable-static --disable-shared
--disable-curve-keygen --enable-curve --disable-drafts --disable-libunwind --with-libsodium
--disable-libbsd --disable-perf
--without-pgm --without-norm --without-vmci --without-docs --with-pic --disable-Werror
"CC=${deps_cc}" "CXX=${deps_cxx}" "CFLAGS=-fstack-protector ${deps_CFLAGS}" "CXXFLAGS=-fstack-protector ${deps_CXXFLAGS}"
${cross_extra}
@ -604,7 +522,7 @@ add_static_target(libzmq zmq_external libzmq.a)
set(libzmq_link_libs "sodium")
if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
list(APPEND libzmq_link_libs iphlpapi)
list(APPEND libzmq_link_libs iphlpapi ws2_32)
endif()
set_target_properties(libzmq PROPERTIES
@ -614,16 +532,12 @@ set_target_properties(libzmq PROPERTIES
set(curl_extra)
if(WIN32)
set(curl_ssl_opts --without-ssl --with-schannel)
elseif(APPLE)
set(curl_ssl_opts --without-ssl --with-secure-transport)
if(APPLE)
if(IOS)
# This CPP crap shouldn't be necessary but is because Apple's toolchain is trash
set(curl_extra "LDFLAGS=-L${DEPS_DESTDIR}/lib -isysroot ${CMAKE_OSX_SYSROOT}" CPP=cpp)
endif()
else()
set(curl_ssl_opts --with-ssl=${DEPS_DESTDIR})
set(curl_extra "LIBS=-pthread")
endif()
@ -655,7 +569,7 @@ foreach(curl_arch ${curl_arches})
build_external(curl
TARGET_SUFFIX ${curl_target_suffix}
DEPENDS openssl_external zlib_external
DEPENDS zlib_external
CONFIGURE_COMMAND ./configure ${cross_host} ${cross_extra} --prefix=${curl_prefix} --disable-shared
--enable-static --disable-ares --disable-ftp --disable-ldap --disable-laps --disable-rtsp
--disable-dict --disable-telnet --disable-tftp --disable-pop3 --disable-imap --disable-smb
@ -663,8 +577,9 @@ foreach(curl_arch ${curl_arches})
--enable-ipv6 --disable-threaded-resolver --disable-pthreads --disable-verbose --disable-sspi
--enable-crypto-auth --disable-ntlm-wb --disable-tls-srp --disable-unix-sockets --disable-cookies
--enable-http-auth --enable-doh --disable-mime --enable-dateparse --disable-netrc --without-libidn2
--disable-progress-meter --without-brotli --with-zlib=${DEPS_DESTDIR} ${curl_ssl_opts}
--without-libmetalink --without-librtmp --disable-versioned-symbols --enable-hidden-symbols
--disable-progress-meter --without-brotli --with-zlib=${DEPS_DESTDIR}
--without-ssl --without-schannel --without-secure-transport
--without-librtmp --disable-versioned-symbols --enable-hidden-symbols
--without-zsh-functions-dir --without-fish-functions-dir
"CC=${deps_cc}" "CFLAGS=${deps_noarch_CFLAGS}${cflags_extra}" ${curl_extra}
BUILD_COMMAND true
@ -693,9 +608,9 @@ endif()
add_static_target(CURL::libcurl curl_external libcurl.a)
set(libcurl_link_libs zlib)
if(CMAKE_CROSSCOMPILING AND ARCH_TRIPLET MATCHES mingw)
list(APPEND libcurl_link_libs crypt32)
list(APPEND libcurl_link_libs ws2_32)
elseif(APPLE)
list(APPEND libcurl_link_libs "-framework Security")
list(APPEND libcurl_link_libs "-framework SystemConfiguration")
endif()
set_target_properties(CURL::libcurl PROPERTIES
INTERFACE_LINK_LIBRARIES "${libcurl_link_libs}"

View File

@ -1,51 +0,0 @@
# Copyright (c) 2014-2018, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function (write_static_version_header hash)
set(VERSIONTAG "${hash}")
configure_file("${CMAKE_SOURCE_DIR}/src/version.cpp.in" "${CMAKE_BINARY_DIR}/version.cpp")
endfunction ()
find_package(Git QUIET)
if (GIT_FOUND OR Git_FOUND)
message(STATUS "Found Git: ${GIT_EXECUTABLE}")
set(VERSIONTAG "@VERSIONTAG@") # Will be replaced again by GenVersion.cmake, below.
configure_file("${CMAKE_SOURCE_DIR}/src/version.cpp.in" "${CMAKE_BINARY_DIR}/version.cpp.in")
add_custom_command(
OUTPUT "${CMAKE_BINARY_DIR}/version.cpp"
COMMAND "${CMAKE_COMMAND}"
"-D" "GIT=${GIT_EXECUTABLE}"
"-P" "${CMAKE_SOURCE_DIR}/cmake/GenVersion.cmake"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
DEPENDS "${CMAKE_BINARY_DIR}/version.cpp.in")
else()
message(WARNING "Git was not found; setting release tag to 'unknown'")
write_static_version_header("unknown")
endif ()
add_custom_target(genversion ALL
DEPENDS "${CMAKE_BINARY_DIR}/version.cpp")

View File

@ -23,7 +23,6 @@ brew "zmq"
brew "libpgm"
brew "unbound"
brew "libsodium"
brew "miniupnpc"
brew "readline"
brew "ldns"
brew "expat"

View File

@ -37,6 +37,7 @@
#include <iostream>
#include <any>
#include <unordered_map>
#include <optional>
#ifdef __OpenBSD__
#include <stdio.h>
#endif

View File

@ -1,45 +0,0 @@
// Copyright (c) 2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
namespace epee
{
namespace fnv
{
inline uint64_t FNV1a(const char *ptr, size_t sz)
{
uint64_t h = 0xcbf29ce484222325;
for (size_t i = 0; i < sz; ++i)
h = (h ^ *(const uint8_t*)ptr++) * 0x100000001b3;
return h;
}
}
}

View File

@ -1,227 +0,0 @@
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
//
#ifndef _GZIP_ENCODING_H_
#define _GZIP_ENCODING_H_
#include "net/http_client_base.h"
#include "zlib/zlib.h"
//#include "http.h"
namespace epee
{
namespace net_utils
{
class content_encoding_gzip: public i_sub_handler
{
public:
/*! \brief
* Function content_encoding_gzip : Constructor
*
*/
inline
content_encoding_gzip(i_target_handler* powner_filter, bool is_deflate_mode = false):m_powner_filter(powner_filter),
m_is_stream_ended(false),
m_is_deflate_mode(is_deflate_mode),
m_is_first_update_in(true)
{
memset(&m_zstream_in, 0, sizeof(m_zstream_in));
memset(&m_zstream_out, 0, sizeof(m_zstream_out));
int ret = 0;
if(is_deflate_mode)
{
ret = inflateInit(&m_zstream_in);
ret = deflateInit(&m_zstream_out, Z_DEFAULT_COMPRESSION);
}else
{
ret = inflateInit2(&m_zstream_in, 0x1F);
ret = deflateInit2(&m_zstream_out, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 0x1F, 8, Z_DEFAULT_STRATEGY);
}
}
/*! \brief
* Function content_encoding_gzip : Destructor
*
*/
inline
~content_encoding_gzip()
{
inflateEnd(& m_zstream_in );
deflateEnd(& m_zstream_out );
}
/*! \brief
* Function update_in : Entry point for income data
*
*/
inline
virtual bool update_in( std::string& piece_of_transfer)
{
bool is_first_time_here = m_is_first_update_in;
m_is_first_update_in = false;
if(m_pre_decode.size())
m_pre_decode += piece_of_transfer;
else
m_pre_decode.swap(piece_of_transfer);
piece_of_transfer.clear();
std::string decode_summary_buff;
size_t ungzip_size = m_pre_decode.size() * 0x30;
std::string current_decode_buff(ungzip_size, 'X');
//Here the cycle is introduced where we unpack the buffer, the cycle is required
//because of the case where if after unpacking the data will exceed the awaited size, we will not halt with error
bool continue_unpacking = true;
bool first_step = true;
while(m_pre_decode.size() && continue_unpacking)
{
//fill buffers
m_zstream_in.next_in = (Bytef*)m_pre_decode.data();
m_zstream_in.avail_in = (uInt)m_pre_decode.size();
m_zstream_in.next_out = (Bytef*)current_decode_buff.data();
m_zstream_in.avail_out = (uInt)ungzip_size;
int flag = Z_SYNC_FLUSH;
int ret = inflate(&m_zstream_in, flag);
CHECK_AND_ASSERT_MES(ret>=0 || m_zstream_in.avail_out ||m_is_deflate_mode, false, "content_encoding_gzip::update_in() Failed to inflate. err = " << ret);
if(Z_STREAM_END == ret)
m_is_stream_ended = true;
else if(Z_DATA_ERROR == ret && is_first_time_here && m_is_deflate_mode&& first_step)
{
// some servers (notably Apache with mod_deflate) don't generate zlib headers
// insert a dummy header and try again
static char dummy_head[2] =
{
0x8 + 0x7 * 0x10,
(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,
};
inflateReset(&m_zstream_in);
m_zstream_in.next_in = (Bytef*) dummy_head;
m_zstream_in.avail_in = sizeof(dummy_head);
ret = inflate(&m_zstream_in, Z_NO_FLUSH);
if (ret != Z_OK)
{
LOCAL_ASSERT(0);
m_pre_decode.swap(piece_of_transfer);
return false;
}
m_zstream_in.next_in = (Bytef*)m_pre_decode.data();
m_zstream_in.avail_in = (uInt)m_pre_decode.size();
ret = inflate(&m_zstream_in, Z_NO_FLUSH);
if (ret != Z_OK)
{
LOCAL_ASSERT(0);
m_pre_decode.swap(piece_of_transfer);
return false;
}
}
//leave only unpacked part in the output buffer to start with it the next time
m_pre_decode.erase(0, m_pre_decode.size()-m_zstream_in.avail_in);
//if decoder gave nothing to return, then everything is ahead, now simply break
if(ungzip_size == m_zstream_in.avail_out)
break;
//decode_buff currently stores data parts that were unpacked, fix this size
current_decode_buff.resize(ungzip_size - m_zstream_in.avail_out);
if(decode_summary_buff.size())
decode_summary_buff += current_decode_buff;
else
current_decode_buff.swap(decode_summary_buff);
current_decode_buff.resize(ungzip_size);
first_step = false;
}
//Process these data if required
bool res = true;
res = m_powner_filter->handle_target_data(decode_summary_buff);
return true;
}
/*! \brief
* Function stop : Entry point for stop signal and flushing cached data buffer.
*
*/
inline
virtual void stop(std::string& collect_remains)
{
}
protected:
private:
/*! \brief
* Pointer to parent HTTP-parser
*/
i_target_handler* m_powner_filter;
/*! \brief
* ZLIB object for income stream
*/
z_stream m_zstream_in;
/*! \brief
* ZLIB object for outcome stream
*/
z_stream m_zstream_out;
/*! \brief
* Data that could not be unpacked immediately, left to wait for the next packet of data
*/
std::string m_pre_decode;
/*! \brief
* The data are accumulated for a package in the buffer to send the web client
*/
std::string m_pre_encode;
/*! \brief
* Signals that stream looks like ended
*/
bool m_is_stream_ended;
/*! \brief
* If this flag is set, income data is in HTTP-deflate mode
*/
bool m_is_deflate_mode;
/*! \brief
* Marks that it is a first data packet
*/
bool m_is_first_update_in;
};
}
}
#endif //_GZIP_ENCODING_H_

View File

@ -1,76 +0,0 @@
// Copyright (c) 2017-2018, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include <array>
#include <cstdint>
#include <iosfwd>
#include <string>
#include <string_view>
#include <vector>
#include "wipeable_string.h"
#include "span.h"
namespace epee
{
struct to_hex
{
//! \return A std::string containing hex of `src`.
static std::string string(const span<const std::uint8_t> src);
//! \return A epee::wipeable_string containing hex of `src`.
static epee::wipeable_string wipeable_string(const span<const std::uint8_t> src);
template<typename T> static epee::wipeable_string wipeable_string(const T &pod) { return wipeable_string(span<const uint8_t>((const uint8_t*)&pod, sizeof(pod))); }
//! \return An array containing hex of `src`.
template<std::size_t N>
static std::array<char, N * 2> array(const std::array<std::uint8_t, N>& src) noexcept
{
std::array<char, N * 2> out{{}};
static_assert(N <= 128, "keep the stack size down");
buffer_unchecked(out.data(), {src.data(), src.size()});
return out;
}
//! Append `src` as hex to `out`.
static void buffer(std::ostream& out, const span<const std::uint8_t> src);
private:
template<typename T> T static convert(const span<const std::uint8_t> src);
//! Write `src` bytes as hex to `out`. `out` must be twice the length
static void buffer_unchecked(char* out, const span<const std::uint8_t> src) noexcept;
};
struct from_hex
{
//! \return An std::vector of unsigned integers from the `src`
static std::vector<uint8_t> vector(std::string_view src);
};
}

View File

@ -1,93 +0,0 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2005 - DINH Viet Hoa
* 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 libEtPan! project 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 AUTHORS 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 AUTHORS 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.
*/
/* hmac-md5.h -- HMAC_MD5 functions
*/
/*
* $Id: hmac-md5.h,v 1.1.1.1 2005/03/18 20:17:28 zautrix Exp $
*/
#ifndef HMAC_MD5_H
#define HMAC_MD5_H 1
namespace md5
{
#define HMAC_MD5_SIZE 16
/* intermediate MD5 context */
typedef struct HMAC_MD5_CTX_s {
MD5_CTX ictx, octx;
} HMAC_MD5_CTX;
/* intermediate HMAC state
* values stored in network byte order (Big Endian)
*/
typedef struct HMAC_MD5_STATE_s {
UINT4 istate[4];
UINT4 ostate[4];
} HMAC_MD5_STATE;
/* One step hmac computation
*
* digest may be same as text or key
*/
void hmac_md5(const unsigned char *text, int text_len,
const unsigned char *key, int key_len,
unsigned char digest[HMAC_MD5_SIZE]);
/* create context from key
*/
void hmac_md5_init(HMAC_MD5_CTX *hmac,
const unsigned char *key, int key_len);
/* precalculate intermediate state from key
*/
void hmac_md5_precalc(HMAC_MD5_STATE *hmac,
const unsigned char *key, int key_len);
/* initialize context from intermediate state
*/
void hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state);
#define hmac_md5_update(hmac, text, text_len) MD5Update(&(hmac)->ictx, (text), (text_len))
/* finish hmac from intermediate result. Intermediate result is zeroed.
*/
void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
HMAC_MD5_CTX *hmac);
}
#endif /* HMAC_MD5_H */

View File

@ -155,6 +155,18 @@ static inline uint64_t div128_64(uint64_t dividend_hi, uint64_t dividend_lo, uin
return remainder;
}
// Calculates a*b/c, using 128-bit precision to avoid overflow. This assumes that the result is
// 64-bits, but only checks it (via assertion) in debug builds. As such you should only call this
// when this is true: for instance, when c is known to be greater than either a or b.
static inline uint64_t mul128_div64(uint64_t a, uint64_t b, uint64_t c) {
uint64_t hi;
uint64_t lo = mul128(a, b, &hi);
uint64_t resulthi, resultlo;
div128_64(hi, lo, c, &resulthi, &resultlo);
assert(resulthi == 0);
return resultlo;
}
#define IDENT16(x) ((uint16_t) (x))
#define IDENT32(x) ((uint32_t) (x))
#define IDENT64(x) ((uint64_t) (x))

View File

@ -1,97 +0,0 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2005 - DINH Viet Hoa
* 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 libEtPan! project 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 AUTHORS 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 AUTHORS 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.
*/
/*
* $Id: md5.h,v 1.1.1.1 2005/03/18 20:17:27 zautrix Exp $
*/
/* MD5.H - header file for MD5C.C
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#ifndef MD5_H
#define MD5_H
#include "md5global.h"
namespace md5
{
/* MD5 context. */
typedef struct {
UINT4 state[4]; /* state (ABCD) */
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
unsigned char buffer[64]; /* input buffer */
} MD5_CTX;
static void MD5Init(MD5_CTX * context);
static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen );
static void MD5Final ( unsigned char digest[16], MD5_CTX *context );
static inline void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest);
inline bool md5( unsigned char *input, int ilen, unsigned char output[16] )
{
MD5_CTX ctx;
MD5Init( &ctx );
MD5Update( &ctx, input, ilen );
MD5Final( output, &ctx);
memwipe( &ctx, sizeof( MD5_CTX ));
return true;
}
}
#include "md5_l.inl"
#endif

View File

@ -1,560 +0,0 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2005 - DINH Viet Hoa
* 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 libEtPan! project 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 AUTHORS 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 AUTHORS 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.
*/
/*
* $Id: md5.c,v 1.1.1.1 2005/03/18 20:17:27 zautrix Exp $
*/
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
*/
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
rights reserved.
License to copy and use this software is granted provided that it
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
Algorithm" in all material mentioning or referencing this software
or this function.
License is also granted to make and use derivative works provided
that such works are identified as "derived from the RSA Data
Security, Inc. MD5 Message-Digest Algorithm" in all material
mentioning or referencing the derived work.
RSA Data Security, Inc. makes no representations concerning either
the merchantability of this software or the suitability of this
software for any particular purpose. It is provided "as is"
without express or implied warranty of any kind.
These notices must be retained in any copies of any part of this
documentation and/or software.
*/
#ifdef _WIN32
# include <winsock2.h>
#else
# include <arpa/inet.h>
#endif
#include "md5global.h"
#include "md5_l.h"
#include "hmac-md5.h"
namespace md5
{
/* Constants for MD5Transform routine.
*/
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21
/*
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
static void Encode PROTO_LIST
((unsigned char *, UINT4 *, unsigned int));
static void Decode PROTO_LIST
((UINT4 *, unsigned char *, unsigned int));
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
*/
static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
output[i] = input[i];
}
/* Note: Replace "for loop" with standard memset if possible.
*/
static void MD5_memset (POINTER output, int value, unsigned int len)
{
unsigned int i;
for (i = 0; i < len; i++)
((char *)output)[i] = (char)value;
}
static void MD5Transform (UINT4 state[4], unsigned char block[64]);
static unsigned char* PADDING()
{
static unsigned char local_PADDING[64] = {
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
return local_PADDING;
}
/* F, G, H and I are basic MD5 functions.
*/
#ifdef I
/* This might be defined via NANA */
#undef I
#endif
#define MD5_M_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define MD5_M_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define MD5_M_H(x, y, z) ((x) ^ (y) ^ (z))
#define MD5_M_I(x, y, z) ((y) ^ ((x) | (~z)))
/* ROTATE_LEFT rotates x left n bits.
*/
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
Rotation is separate from addition to prevent recomputation.
*/
#define FF(a, b, c, d, x, s, ac) { (a) += MD5_M_F ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define GG(a, b, c, d, x, s, ac) { (a) += MD5_M_G ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define HH(a, b, c, d, x, s, ac) { (a) += MD5_M_H ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
#define II(a, b, c, d, x, s, ac) { (a) += MD5_M_I ((b), (c), (d)) + (x) + (UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
/* MD5 initialization. Begins an MD5 operation, writing a new context.
*/
static void MD5Init(MD5_CTX * context)
{
context->count[0] = context->count[1] = 0;
/* Load magic initialization constants.
*/
context->state[0] = 0x67452301;
context->state[1] = 0xefcdab89;
context->state[2] = 0x98badcfe;
context->state[3] = 0x10325476;
}
/* MD5 block update operation. Continues an MD5 message-digest
operation, processing another message block, and updating the context.
*/
static void MD5Update( MD5_CTX *context, const unsigned char *input, unsigned int inputLen )
{
unsigned int i, index, partLen;
/* Compute number of bytes mod 64 */
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
/* Update number of bits */
if ((context->count[0] += ((UINT4)inputLen << 3))
< ((UINT4)inputLen << 3))
context->count[1]++;
context->count[1] += ((UINT4)inputLen >> 29);
partLen = 64 - index;
/* Transform as many times as possible.
*/
if (inputLen >= partLen)
{
MD5_memcpy( (POINTER)&context->buffer[index], (POINTER)input, partLen );
MD5Transform( context->state, context->buffer );
for (i = partLen; i + 63 < inputLen; i += 64)
MD5Transform (context->state, (unsigned char*)&input[i]);
index = 0;
}
else
i = 0;
/* Buffer remaining input */
MD5_memcpy( (POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i );
}
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
a multiple of 4.
*/
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4) {
output[j] = (unsigned char)(input[i] & 0xff);
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
}
}
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
a multiple of 4.
*/
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
{
unsigned int i, j;
for (i = 0, j = 0; j < len; i++, j += 4)
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16)
| (((UINT4)input[j+3]) << 24);
}
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
the message digest and zeroizing the context.
*/
static void MD5Final ( unsigned char digest[16], MD5_CTX *context )
{
unsigned char bits[8];
unsigned int index, padLen;
/* Save number of bits */
Encode (bits, context->count, 8);
/* Pad out to 56 mod 64.
*/
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
padLen = (index < 56) ? (56 - index) : (120 - index);
MD5Update (context, PADDING(), padLen);
/* Append length (before padding) */
MD5Update (context, bits, 8);
/* Store state in digest */
Encode (digest, context->state, 16);
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)context, 0, sizeof (*context));
}
/* MD5 basic transformation. Transforms state based on block.
*/
static void MD5Transform (UINT4 state[4], unsigned char block[64])
{
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
Decode (x, block, 64);
/* Round 1 */
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
/* Round 2 */
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
/* Round 3 */
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
/* Round 4 */
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
/* Zeroize sensitive information.
*/
MD5_memset ((POINTER)x, 0, sizeof (x));
}
/* Note: Replace "for loop" with standard memcpy if possible.
*/
inline
void hmac_md5_init(HMAC_MD5_CTX *hmac,
const unsigned char *key,
int key_len)
{
unsigned char k_ipad[65]; /* inner padding -
* key XORd with ipad
*/
unsigned char k_opad[65]; /* outer padding -
* key XORd with opad
*/
unsigned char tk[16];
int i;
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64) {
MD5_CTX tctx;
MD5Init(&tctx);
MD5Update(&tctx, key, key_len);
MD5Final(tk, &tctx);
key = tk;
key_len = 16;
}
/*
* the HMAC_MD5 transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected
*/
/* start out by storing key in pads */
MD5_memset(k_ipad, '\0', sizeof k_ipad);
MD5_memset(k_opad, '\0', sizeof k_opad);
MD5_memcpy( k_ipad, (POINTER)key, key_len);
MD5_memcpy( k_opad, (POINTER)key, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
MD5Init(&hmac->ictx); /* init inner context */
MD5Update(&hmac->ictx, k_ipad, 64); /* apply inner pad */
MD5Init(&hmac->octx); /* init outer context */
MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
/* scrub the pads and key context (if used) */
MD5_memset( (POINTER)&k_ipad, 0, sizeof(k_ipad));
MD5_memset( (POINTER)&k_opad, 0, sizeof(k_opad));
MD5_memset( (POINTER)&tk, 0, sizeof(tk));
/* and we're done. */
}
/* The precalc and import routines here rely on the fact that we pad
* the key out to 64 bytes and use that to initialize the md5
* contexts, and that updating an md5 context with 64 bytes of data
* leaves nothing left over; all of the interesting state is contained
* in the state field, and none of it is left over in the count and
* buffer fields. So all we have to do is save the state field; we
* can zero the others when we reload it. Which is why the decision
* was made to pad the key out to 64 bytes in the first place. */
inline
void hmac_md5_precalc(HMAC_MD5_STATE *state,
const unsigned char *key,
int key_len)
{
HMAC_MD5_CTX hmac;
unsigned lupe;
hmac_md5_init(&hmac, key, key_len);
for (lupe = 0; lupe < 4; lupe++) {
state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
}
MD5_memset( (POINTER)&hmac, 0, sizeof(hmac));
}
inline
void hmac_md5_import(HMAC_MD5_CTX *hmac,
HMAC_MD5_STATE *state)
{
unsigned lupe;
MD5_memset( (POINTER)hmac, 0, sizeof(HMAC_MD5_CTX));
for (lupe = 0; lupe < 4; lupe++) {
hmac->ictx.state[lupe] = ntohl(state->istate[lupe]);
hmac->octx.state[lupe] = ntohl(state->ostate[lupe]);
}
/* Init the counts to account for our having applied
* 64 bytes of key; this works out to 0x200 (64 << 3; see
* MD5Update above...) */
hmac->ictx.count[0] = hmac->octx.count[0] = 0x200;
}
inline
void hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
HMAC_MD5_CTX *hmac)
{
MD5Final(digest, &hmac->ictx); /* Finalize inner md5 */
MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */
MD5Final(digest, &hmac->octx); /* Finalize outer md5 */
}
void hmac_md5(const unsigned char* text, int text_len, const unsigned char* key, int key_len, unsigned char *digest)
{
MD5_CTX context;
unsigned char k_ipad[65]; /* inner padding -
* key XORd with ipad
*/
unsigned char k_opad[65]; /* outer padding -
* key XORd with opad
*/
unsigned char tk[16];
int i;
/* if key is longer than 64 bytes reset it to key=MD5(key) */
if (key_len > 64) {
MD5_CTX tctx;
MD5Init(&tctx);
MD5Update(&tctx, key, key_len);
MD5Final(tk, &tctx);
key = tk;
key_len = 16;
}
/*
* the HMAC_MD5 transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, text))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected
*/
/* start out by storing key in pads */
MD5_memset(k_ipad, '\0', sizeof k_ipad);
MD5_memset(k_opad, '\0', sizeof k_opad);
MD5_memcpy( k_ipad, (POINTER)key, key_len);
MD5_memcpy( k_opad, (POINTER)key, key_len);
/* XOR key with ipad and opad values */
for (i=0; i<64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/*
* perform inner MD5
*/
MD5Init(&context); /* init context for 1st
* pass */
MD5Update(&context, k_ipad, 64); /* start with inner pad */
MD5Update(&context, text, text_len); /* then text of datagram */
MD5Final(digest, &context); /* finish up 1st pass */
/*
* perform outer MD5
*/
MD5Init(&context); /* init context for 2nd
* pass */
MD5Update(&context, k_opad, 64); /* start with outer pad */
MD5Update(&context, digest, 16); /* then results of 1st
* hash */
MD5Final(digest, &context); /* finish up 2nd pass */
}
}

View File

@ -1,77 +0,0 @@
/*
* libEtPan! -- a mail stuff library
*
* Copyright (C) 2001, 2005 - DINH Viet Hoa
* 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 libEtPan! project 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 AUTHORS 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 AUTHORS 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.
*/
/*
* $Id: md5global.h,v 1.1.1.1 2005/03/18 20:17:28 zautrix Exp $
*/
/* GLOBAL.H - RSAREF types and constants
*/
#ifndef MD5GLOBAL_H
#define MD5GLOBAL_H
namespace md5
{
/* PROTOTYPES should be set to one if and only if the compiler supports
function argument prototyping.
The following makes PROTOTYPES default to 0 if it has not already
been defined with C compiler flags.
*/
#ifndef PROTOTYPES
#define PROTOTYPES 0
#endif
/* POINTER defines a generic pointer type */
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
//typedef unsigned long int UINT4;
typedef unsigned int UINT4;
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
returns an empty list.
*/
#if PROTOTYPES
#define PROTO_LIST(list) list
#else
#define PROTO_LIST(list) ()
#endif
}
#endif

View File

@ -1,161 +0,0 @@
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
//
#pragma once
#include <limits>
#include <thread>
#include <chrono>
#include <memory>
#include <vector>
#include <algorithm>
namespace epee
{
#define STD_TRY_BEGIN() try {
#define STD_TRY_CATCH(where_, ret_val) \
} \
catch (const std::exception &e) \
{ \
LOG_ERROR("EXCEPTION: " << where_ << ", mes: "<< e.what()); \
return ret_val; \
} \
catch (...) \
{ \
LOG_ERROR("EXCEPTION: " << where_ ); \
return ret_val; \
}
namespace misc_utils
{
template<typename t_type>
t_type get_max_t_val(t_type t)
{
return (std::numeric_limits<t_type>::max)();
}
template<typename t_iterator>
t_iterator move_it_forward(t_iterator it, size_t count)
{
while(count--)
it++;
return it;
}
template<typename t_iterator>
t_iterator move_it_backward(t_iterator it, size_t count)
{
while(count--)
it--;
return it;
}
// TEMPLATE STRUCT less
template<class _Ty>
struct less_as_pod
: public std::binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return memcmp(&_Left, &_Right, sizeof(_Left)) < 0;
}
};
template<class _Ty>
bool is_less_as_pod(const _Ty& _Left, const _Ty& _Right)
{ // apply operator< to operands
return memcmp(&_Left, &_Right, sizeof(_Left)) < 0;
}
inline
void sleep_no_w(long ms)
{
std::this_thread::sleep_for(std::chrono::milliseconds{ms});
}
template<class type_vec_type>
type_vec_type median(std::vector<type_vec_type> &v)
{
if(v.empty())
return type_vec_type{};
if(v.size() == 1)
return v[0];
size_t n = (v.size()) / 2;
std::sort(v.begin(), v.end());
//nth_element(v.begin(), v.begin()+n-1, v.end());
if(v.size()%2)
{//1, 3, 5...
return v[n];
}else
{//2, 4, 6...
return (v[n-1] + v[n])/2;
}
}
/************************************************************************/
/* */
/************************************************************************/
struct call_befor_die_base
{
virtual ~call_befor_die_base(){}
};
using auto_scope_leave_caller = std::shared_ptr<call_befor_die_base>;
template<class t_scope_leave_handler>
struct call_befor_die: public call_befor_die_base
{
t_scope_leave_handler m_func;
call_befor_die(t_scope_leave_handler f):m_func(f)
{}
~call_befor_die()
{
try { m_func(); }
catch (...) { /* ignore */ }
}
};
template<class t_scope_leave_handler>
auto_scope_leave_caller create_scope_leave_handler(t_scope_leave_handler f)
{
auto_scope_leave_caller slc(new call_befor_die<t_scope_leave_handler>(f));
return slc;
}
}
}

View File

@ -37,7 +37,7 @@
#include <boost/asio/steady_timer.hpp>
#include "../warnings.h"
#include "../string_tools.h"
#include "../misc_language.h"
#include "../scope_leaver.h"
#include "local_ip.h"
#include "../pragma_comp_defs.h"
@ -431,7 +431,7 @@ PRAGMA_WARNING_DISABLE_VS(4355)
//ask it inside(!) critical region if we still able to go in event wait...
size_t cnt = GET_IO_SERVICE(socket()).poll_one();
if(!cnt)
misc_utils::sleep_no_w(1);
std::this_thread::sleep_for(1ms);
}
return true;
@ -1200,7 +1200,7 @@ POP_WARNINGS
// error path, if e or exception
assert(m_state != nullptr); // always set in constructor
MERROR("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
misc_utils::sleep_no_w(100);
std::this_thread::sleep_for(100ms);
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type));
current_acceptor->async_accept((*current_new_connection)->socket(),
boost::bind(accept_function_pointer, this,
@ -1315,7 +1315,7 @@ POP_WARNINGS
connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size());
connections_mutex.unlock();
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ std::lock_guard lock{connections_mutex}; connections_.erase(new_connection_l); });
auto scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ std::lock_guard lock{connections_mutex}; connections_.erase(new_connection_l); });
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
bool try_ipv6 = false;
@ -1431,7 +1431,7 @@ POP_WARNINGS
connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size());
connections_mutex.unlock();
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ std::lock_guard lock{connections_mutex}; connections_.erase(new_connection_l); });
auto scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ std::lock_guard lock{connections_mutex}; connections_.erase(new_connection_l); });
boost::asio::ip::tcp::socket& sock_ = new_connection_l->socket();
bool try_ipv6 = false;

View File

@ -36,6 +36,7 @@
#include "levin_base.h"
#include "buffer.h"
#include "../misc_language.h"
#include "../scope_leaver.h"
#include "../int-util.h"
#include <random>
@ -323,7 +324,7 @@ public:
for (size_t i = 0; i < 60 * 1000 / 100 && 0 != m_wait_count; ++i)
{
misc_utils::sleep_no_w(100);
std::this_thread::sleep_for(100ms);
}
CHECK_AND_ASSERT_MES_NO_RET(0 == m_wait_count, "Failed to wait for operation completion. m_wait_count = " << m_wait_count);
@ -385,7 +386,7 @@ public:
void request_callback()
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
[this] { return finish_outer_call(); });
m_pservice_endpoint->request_callback();
@ -616,7 +617,7 @@ public:
template<class callback_t>
bool async_invoke(int command, const epee::span<const uint8_t> in_buff, const callback_t &cb, std::chrono::nanoseconds timeout = 0ns)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
[this] { return finish_outer_call(); });
if(timeout == 0ns)
@ -671,7 +672,7 @@ public:
int invoke(int command, const epee::span<const uint8_t> in_buff, std::string& buff_out)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
[this] { return finish_outer_call(); });
if(m_deletion_initiated)
@ -722,7 +723,7 @@ public:
int notify(int command, const epee::span<const uint8_t> in_buff)
{
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
[this] { return finish_outer_call(); });
if(m_deletion_initiated)
@ -750,7 +751,7 @@ public:
\return 1 on success */
int send(shared_sv message)
{
const misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
auto scope_exit_handler = misc_utils::create_scope_leave_handler(
[this] { return finish_outer_call(); });
if(m_deletion_initiated)

View File

@ -24,59 +24,40 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
#include "misc_language.h"
namespace epee
namespace epee::misc_utils
{
namespace tests
/************************************************************************/
/* */
/************************************************************************/
template <typename Callback>
class scope_leave_handler_impl
{
bool test_median()
Callback m_func;
public:
scope_leave_handler_impl(Callback f) : m_func(std::move(f)) {}
~scope_leave_handler_impl()
{
LOG_PRINT_L0("Testing median");
std::vector<size_t> sz;
size_t m = misc_utils::median(sz);
CHECK_AND_ASSERT_MES(m == 0, false, "test failed");
sz.push_back(1);
m = misc_utils::median(sz);
CHECK_AND_ASSERT_MES(m == 1, false, "test failed");
sz.push_back(10);
m = misc_utils::median(sz);
CHECK_AND_ASSERT_MES(m == 5, false, "test failed");
sz.clear();
sz.resize(3);
sz[0] = 0;
sz[1] = 9;
sz[2] = 3;
m = misc_utils::median(sz);
CHECK_AND_ASSERT_MES(m == 3, false, "test failed");
sz.clear();
sz.resize(4);
sz[0] = 77;
sz[1] = 9;
sz[2] = 22;
sz[3] = 60;
m = misc_utils::median(sz);
CHECK_AND_ASSERT_MES(m == 41, false, "test failed");
sz.clear();
sz.resize(5);
sz[0] = 77;
sz[1] = 9;
sz[2] = 22;
sz[3] = 60;
sz[4] = 11;
m = misc_utils::median(sz);
CHECK_AND_ASSERT_MES(m == 22, false, "test failed");
return true;
try { m_func(); }
catch (...) { /* ignore */ }
}
}
}
// Moveable, Non-copyable
scope_leave_handler_impl(const scope_leave_handler_impl&) = delete;
scope_leave_handler_impl& operator=(const scope_leave_handler_impl&) = delete;
scope_leave_handler_impl(scope_leave_handler_impl&&) = default;
scope_leave_handler_impl& operator=(scope_leave_handler_impl&&) = default;
};
template <typename Callback>
auto create_scope_leave_handler(Callback f)
{
return scope_leave_handler_impl(std::move(f));
}
}

View File

@ -158,8 +158,8 @@ public: \
using int_t = std::underlying_type_t<enum_t>; \
int_t int_value = is_store ? static_cast<int_t>(this_ref.enum_) : 0; \
epee::serialization::perform_serialize<is_store>(int_value, stg, parent_section, #enum_); \
if (!is_store) \
const_cast<enum_t&>(this_ref.enum_) = static_cast<enum_t>(int_value); \
if constexpr (!is_store) \
this_ref.enum_ = static_cast<enum_t>(int_value); \
} while(0);
// Stashes `this` in the storage object's context for a dependent type that needs to access it.

View File

@ -82,19 +82,19 @@ namespace epee
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
static bool serialize_t_val(const t_type& d, t_storage& stg, section* parent_section, const char* pname)
bool serialize_t_val(const t_type& d, t_storage& stg, section* parent_section, const char* pname)
{
return stg.set_value(pname, d, parent_section);
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
static bool unserialize_t_val(t_type& d, t_storage& stg, section* parent_section, const char* pname)
bool unserialize_t_val(t_type& d, t_storage& stg, section* parent_section, const char* pname)
{
return stg.get_value(pname, d, parent_section);
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
static bool serialize_t_val_as_blob(const t_type& d, t_storage& stg, section* parent_section, const char* pname)
bool serialize_t_val_as_blob(const t_type& d, t_storage& stg, section* parent_section, const char* pname)
{
assert_blob_serializable<t_type>();
std::string blob((const char *)&d, sizeof(d));
@ -102,7 +102,7 @@ namespace epee
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
static bool unserialize_t_val_as_blob(t_type& d, t_storage& stg, section* parent_section, const char* pname)
bool unserialize_t_val_as_blob(t_type& d, t_storage& stg, section* parent_section, const char* pname)
{
assert_blob_serializable<t_type>();
std::string blob;
@ -114,7 +114,7 @@ namespace epee
}
//-------------------------------------------------------------------------------------------------------------------
template<class serializible_type, class t_storage>
static bool serialize_t_obj(const serializible_type& obj, t_storage& stg, section* parent_section, const char* pname)
bool serialize_t_obj(const serializible_type& obj, t_storage& stg, section* parent_section, const char* pname)
{
section* child_section = stg.open_section(pname, parent_section, true);
CHECK_AND_ASSERT_MES(child_section, false, "serialize_t_obj: failed to open/create section " << pname);
@ -122,7 +122,7 @@ namespace epee
}
//-------------------------------------------------------------------------------------------------------------------
template<class serializible_type, class t_storage>
static bool unserialize_t_obj(serializible_type& obj, t_storage& stg, section* parent_section, const char* pname)
bool unserialize_t_obj(serializible_type& obj, t_storage& stg, section* parent_section, const char* pname)
{
section* child_section = stg.open_section(pname, parent_section, false);
if(!child_section) return false;
@ -130,7 +130,7 @@ namespace epee
}
//-------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
static bool serialize_stl_container_t_val(const stl_container& container, t_storage& stg, section* parent_section, const char* pname)
bool serialize_stl_container_t_val(const stl_container& container, t_storage& stg, section* parent_section, const char* pname)
{
using T = typename stl_container::value_type;
if(!container.size()) return true;
@ -142,7 +142,7 @@ namespace epee
}
//--------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
static bool unserialize_stl_container_t_val(stl_container& container, t_storage& stg, section* parent_section, const char* pname)
bool unserialize_stl_container_t_val(stl_container& container, t_storage& stg, section* parent_section, const char* pname)
{
using T = typename stl_container::value_type;
container.clear();
@ -158,7 +158,7 @@ namespace epee
}
//--------------------------------------------------------------------------------------------------------------------
template<typename T, size_t Size, class t_storage>
static bool unserialize_stl_container_t_val(std::array<T, Size>& array, t_storage& stg, section* parent_section, const char* pname)
bool unserialize_stl_container_t_val(std::array<T, Size>& array, t_storage& stg, section* parent_section, const char* pname)
{
static_assert(Size > 0, "cannot deserialize empty std::array");
size_t next_i = 0;
@ -171,7 +171,7 @@ namespace epee
}
//--------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
static bool serialize_stl_container_pod_val_as_blob(const stl_container& container, t_storage& stg, section* parent_section, const char* pname)
bool serialize_stl_container_pod_val_as_blob(const stl_container& container, t_storage& stg, section* parent_section, const char* pname)
{
using T = typename stl_container::value_type;
assert_blob_serializable<T>();
@ -190,7 +190,7 @@ namespace epee
}
//--------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
static bool unserialize_stl_container_pod_val_as_blob(stl_container& container, t_storage& stg, section* parent_section, const char* pname)
bool unserialize_stl_container_pod_val_as_blob(stl_container& container, t_storage& stg, section* parent_section, const char* pname)
{
using T = typename stl_container::value_type;
assert_blob_serializable<T>();
@ -220,7 +220,7 @@ namespace epee
}
//--------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
static bool serialize_stl_container_t_obj(const stl_container& container, t_storage& stg, section* parent_section, const char* pname)
bool serialize_stl_container_t_obj(const stl_container& container, t_storage& stg, section* parent_section, const char* pname)
{
if (container.empty()) return true;
auto* sec_array = stg.template make_array_t<section>(pname, parent_section);
@ -233,7 +233,7 @@ namespace epee
}
//--------------------------------------------------------------------------------------------------------------------
template<class stl_container, class t_storage>
static bool unserialize_stl_container_t_obj(stl_container& container, t_storage& stg, section* parent_section, const char* pname)
bool unserialize_stl_container_t_obj(stl_container& container, t_storage& stg, section* parent_section, const char* pname)
{
container.clear();
auto* arr = stg.template get_array<section>(pname, parent_section);
@ -245,7 +245,7 @@ namespace epee
}
//--------------------------------------------------------------------------------------------------------------------
template<typename T, size_t Size, class t_storage>
static bool unserialize_stl_container_t_obj(std::array<T, Size>& out, t_storage& stg, section* parent_section, const char* pname)
bool unserialize_stl_container_t_obj(std::array<T, Size>& out, t_storage& stg, section* parent_section, const char* pname)
{
static_assert(Size > 0, "cannot deserialize empty std::array");
auto* arr = stg.template get_array<section>(pname, parent_section);

View File

@ -1,6 +1,8 @@
#pragma once
#include <vector>
#include <cstddef>
#include <cstdint>
template<typename T, typename Tpod = T>
class Stats

View File

@ -1,4 +1,4 @@
#include <math.h>
#include <cmath>
#include <limits>
#include <algorithm>
#include "stats.h"
@ -15,13 +15,13 @@ enum
bit_kurtosis,
};
static inline double square(double x)
inline double square(double x)
{
return x * x;
}
template<typename T>
static inline double interpolate(T v, T v0, double i0, T v1, double i1)
double interpolate(T v, T v0, double i0, T v1, double i1)
{
return i0 + (i1 - i0) * (v - v0) / (v1 - v0);
}
@ -109,20 +109,30 @@ double Stats<T, Tpod>::get_mean() const
return mean;
}
inline constexpr double T_DIST_CRITICAL_975[101] = {
-1, 12.706, 4.3027, 3.1824, 2.7765, 2.5706, 2.4469, 2.3646, 2.3060, 2.2622, 2.2281, 2.2010, 2.1788, 2.1604, 2.1448, 2.1315,
2.1199, 2.1098, 2.1009, 2.0930, 2.0860, 2.0796, 2.0739, 2.0687, 2.0639, 2.0595, 2.0555, 2.0518, 2.0484, 2.0452, 2.0423, 2.0395,
2.0369, 2.0345, 2.0322, 2.0301, 2.0281, 2.0262, 2.0244, 2.0227, 2.0211, 2.0195, 2.0181, 2.0167, 2.0154, 2.0141, 2.0129, 2.0117,
2.0106, 2.0096, 2.0086, 2.0076, 2.0066, 2.0057, 2.0049, 2.0040, 2.0032, 2.0025, 2.0017, 2.0010, 2.0003, 1.9996, 1.9990, 1.9983,
1.9977, 1.9971, 1.9966, 1.9960, 1.9955, 1.9949, 1.9944, 1.9939, 1.9935, 1.9930, 1.9925, 1.9921, 1.9917, 1.9913, 1.9908, 1.9905,
1.9901, 1.9897, 1.9893, 1.9890, 1.9886, 1.9883, 1.9879, 1.9876, 1.9873, 1.9870, 1.9867, 1.9864, 1.9861, 1.9858, 1.9855, 1.9852,
1.9850, 1.9847, 1.9845, 1.9842, 1.9840,
};
inline constexpr double T_DIST_CRITICAL_995[101] = {
-1, 9.9250, 5.8408, 4.6041, 4.0321, 3.7074, 3.4995, 3.3554, 3.2498, 3.1693, 3.1058, 3.0545, 3.0123, 2.9768, 2.9467, 2.9208, 2.8982,
2.8784, 2.8609, 2.8453, 2.8314, 2.8188, 2.8073, 2.7970, 2.7874, 2.7787, 2.7707, 2.7633, 2.7564, 2.7500, 2.7440, 2.7385, 2.7333,
2.7284, 2.7238, 2.7195, 2.7154, 2.7116, 2.7079, 2.7045, 2.7012, 2.6981, 2.6951, 2.6923, 2.6896, 2.6870, 2.6846, 2.6822, 2.6800,
2.6778, 2.6757, 2.6737, 2.6718, 2.6700, 2.6682, 2.6665, 2.6649, 2.6633, 2.6618, 2.6603, 2.6589, 2.6575, 2.6561, 2.6549, 2.6536,
2.6524, 2.6512, 2.6501, 2.6490, 2.6479, 2.6469, 2.6458, 2.6449, 2.6439, 2.6430, 2.6421, 2.6412, 2.6403, 2.6395, 2.6387, 2.6379,
2.6371, 2.6364, 2.6356, 2.6349, 2.6342, 2.6335, 2.6329, 2.6322, 2.6316, 2.6309, 2.6303, 2.6297, 2.6291, 2.6286, 2.6280, 2.6275,
2.6269, 2.6264, 2.6259,
};
template<typename T, typename Tpod>
double Stats<T, Tpod>::get_cdf95(size_t df) const
{
static const double p[101] = {
-1, 12.706, 4.3027, 3.1824, 2.7765, 2.5706, 2.4469, 2.3646, 2.3060, 2.2622, 2.2281, 2.2010, 2.1788, 2.1604, 2.1448, 2.1315,
2.1199, 2.1098, 2.1009, 2.0930, 2.0860, 2.0796, 2.0739, 2.0687, 2.0639, 2.0595, 2.0555, 2.0518, 2.0484, 2.0452, 2.0423, 2.0395,
2.0369, 2.0345, 2.0322, 2.0301, 2.0281, 2.0262, 2.0244, 2.0227, 2.0211, 2.0195, 2.0181, 2.0167, 2.0154, 2.0141, 2.0129, 2.0117,
2.0106, 2.0096, 2.0086, 2.0076, 2.0066, 2.0057, 2.0049, 2.0040, 2.0032, 2.0025, 2.0017, 2.0010, 2.0003, 1.9996, 1.9990, 1.9983,
1.9977, 1.9971, 1.9966, 1.9960, 1.9955, 1.9949, 1.9944, 1.9939, 1.9935, 1.9930, 1.9925, 1.9921, 1.9917, 1.9913, 1.9908, 1.9905,
1.9901, 1.9897, 1.9893, 1.9890, 1.9886, 1.9883, 1.9879, 1.9876, 1.9873, 1.9870, 1.9867, 1.9864, 1.9861, 1.9858, 1.9855, 1.9852,
1.9850, 1.9847, 1.9845, 1.9842, 1.9840,
};
if (df <= 100)
return p[df];
return T_DIST_CRITICAL_975[df];
if (df <= 120)
return interpolate<size_t>(df, 100, 1.9840, 120, 1.98);
return 1.96;
@ -137,17 +147,8 @@ double Stats<T, Tpod>::get_cdf95(const Stats<T> &other) const
template<typename T, typename Tpod>
double Stats<T, Tpod>::get_cdf99(size_t df) const
{
static const double p[101] = {
-1, 9.9250, 5.8408, 4.6041, 4.0321, 3.7074, 3.4995, 3.3554, 3.2498, 3.1693, 3.1058, 3.0545, 3.0123, 2.9768, 2.9467, 2.9208, 2.8982,
2.8784, 2.8609, 2.8453, 2.8314, 2.8188, 2.8073, 2.7970, 2.7874, 2.7787, 2.7707, 2.7633, 2.7564, 2.7500, 2.7440, 2.7385, 2.7333,
2.7284, 2.7238, 2.7195, 2.7154, 2.7116, 2.7079, 2.7045, 2.7012, 2.6981, 2.6951, 2.6923, 2.6896, 2.6870, 2.6846, 2.6822, 2.6800,
2.6778, 2.6757, 2.6737, 2.6718, 2.6700, 2.6682, 2.6665, 2.6649, 2.6633, 2.6618, 2.6603, 2.6589, 2.6575, 2.6561, 2.6549, 2.6536,
2.6524, 2.6512, 2.6501, 2.6490, 2.6479, 2.6469, 2.6458, 2.6449, 2.6439, 2.6430, 2.6421, 2.6412, 2.6403, 2.6395, 2.6387, 2.6379,
2.6371, 2.6364, 2.6356, 2.6349, 2.6342, 2.6335, 2.6329, 2.6322, 2.6316, 2.6309, 2.6303, 2.6297, 2.6291, 2.6286, 2.6280, 2.6275,
2.6269, 2.6264, 2.6259,
};
if (df <= 100)
return p[df];
return T_DIST_CRITICAL_995[df];
if (df <= 120)
return interpolate<size_t>(df, 100, 2.6529, 120, 2.617);
return 2.576;

View File

@ -24,31 +24,21 @@
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
#include <algorithm>
#include <string>
#include <string_view>
#include "../misc_log_ex.h"
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "serialization"
namespace epee
namespace epee::misc_utils::parse
{
namespace misc_utils
{
namespace parse
{
namespace detail {
// 1: digit
// 2: .eE (floating point)
// 4: alpha
// 8: whitespace
// 16: allowed in float but doesn't necessarily mean it's a float
// 32: \ and " (end of verbatim string)
static const constexpr uint8_t lut[256]={
inline constexpr uint8_t lut[256]={
0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 0, 0, // 16
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
8, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 16, 18, 0, // 48
@ -66,322 +56,12 @@ namespace misc_utils
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const constexpr unsigned char isx[256] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 10, 11, 12, 13, 14, 15, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
};
inline bool isspace(char c)
{
return lut[(uint8_t)c] & 8;
}
inline bool isdigit(char c)
{
return lut[(uint8_t)c] & 1;
}
inline std::string transform_to_escape_sequence(const std::string& src)
{
static const char escaped[] = "\b\f\n\r\t\v\"\\/";
auto it = std::find_first_of(src.begin(), src.end(), escaped, escaped + sizeof(escaped));
if (it == src.end())
return src;
std::string res;
res.reserve(2 * src.size());
res.assign(src.begin(), it);
for(; it!=src.end(); ++it)
{
switch(*it)
{
case '\b': //Backspace (ascii code 08)
res+="\\b"; break;
case '\f': //Form feed (ascii code 0C)
res+="\\f"; break;
case '\n': //New line
res+="\\n"; break;
case '\r': //Carriage return
res+="\\r"; break;
case '\t': //Tab
res+="\\t"; break;
case '\v': //Vertical tab
res+="\\v"; break;
//case '\'': //Apostrophe or single quote
// res+="\\'"; break;
case '"': //Double quote
res+="\\\""; break;
case '\\': //Backslash caracter
res+="\\\\"; break;
case '/': //Backslash caracter
res+="\\/"; break;
default:
res.push_back(*it);
}
}
return res;
}
/*
\b Backspace (ascii code 08)
\f Form feed (ascii code 0C)
\n New line
\r Carriage return
\t Tab
\v Vertical tab
\' Apostrophe or single quote
\" Double quote
\\ Backslash character
*/
template <typename It>
inline void match_string2(It& star_end_string, It buf_end, std::string& val)
{
bool escape_mode = false;
auto it = star_end_string;
++it;
auto fi = it;
while (fi != buf_end && ((lut[(uint8_t)*fi] & 32)) == 0)
++fi;
val.assign(it, fi);
val.reserve(std::distance(star_end_string, buf_end));
it = fi;
for(;it != buf_end;it++)
{
if(escape_mode/*prev_ch == '\\'*/)
{
switch(*it)
{
case 'b': //Backspace (ascii code 08)
val.push_back(0x08);break;
case 'f': //Form feed (ascii code 0C)
val.push_back(0x0C);break;
case 'n': //New line
val.push_back('\n');break;
case 'r': //Carriage return
val.push_back('\r');break;
case 't': //Tab
val.push_back('\t');break;
case 'v': //Vertical tab
val.push_back('\v');break;
case '\'': //Apostrophe or single quote
val.push_back('\'');break;
case '"': //Double quote
val.push_back('"');break;
case '\\': //Backslash character
val.push_back('\\');break;
case '/': //Slash character
val.push_back('/');break;
case 'u': //Unicode code point
if (buf_end - it < 4)
{
ASSERT_MES_AND_THROW("Invalid Unicode escape sequence");
}
else
{
uint32_t dst = 0;
for (int i = 0; i < 4; ++i)
{
const unsigned char tmp = isx[(int)*++it];
CHECK_AND_ASSERT_THROW_MES(tmp != 0xff, "Bad Unicode encoding");
dst = dst << 4 | tmp;
}
// encode as UTF-8
if (dst <= 0x7f)
{
val.push_back(dst);
}
else if (dst <= 0x7ff)
{
val.push_back(0xc0 | (dst >> 6));
val.push_back(0x80 | (dst & 0x3f));
}
else if (dst <= 0xffff)
{
val.push_back(0xe0 | (dst >> 12));
val.push_back(0x80 | ((dst >> 6) & 0x3f));
val.push_back(0x80 | (dst & 0x3f));
}
else
{
ASSERT_MES_AND_THROW("Unicode code point is out or range");
}
}
break;
default:
val.push_back(*it);
LOG_PRINT_L0("Unknown escape sequence :\"\\" << *it << "\"");
}
escape_mode = false;
}else if(*it == '"')
{
star_end_string = it;
return;
}else if(*it == '\\')
{
escape_mode = true;
}
else
{
val.push_back(*it);
}
}
ASSERT_MES_AND_THROW("Failed to match string in json entry: " << std::string(star_end_string, buf_end));
}
template <typename It>
bool match_string(It& star_end_string, It buf_end, std::string& val)
{
try
{
match_string2(star_end_string, buf_end, val);
return true;
}
catch(...)
{
return false;
}
}
template <typename It>
void match_number2(It& star_end_string, It buf_end, std::string_view& val, bool& is_float_val, bool& is_signed_val)
{
val = {};
uint8_t float_flag = 0;
is_signed_val = false;
size_t chars = 0;
auto it = star_end_string;
if (it != buf_end && *it == '-')
{
is_signed_val = true;
++chars;
++it;
}
for(;it != buf_end;it++)
{
const uint8_t flags = lut[(uint8_t)*it];
if (flags & 16)
{
float_flag |= flags;
++chars;
}
else
{
val = std::string_view(&*star_end_string, chars);
if(val.size())
{
star_end_string = --it;
is_float_val = !!(float_flag & 2);
return;
}
else
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
}
}
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
}
template <typename It>
bool match_number(It& star_end_string, It buf_end, std::string_view& val)
{
try
{
bool is_v_float = false;bool is_signed_val = false;
match_number2(star_end_string, buf_end, val, is_v_float, is_signed_val);
return !is_v_float;
}
catch(...)
{
return false;
}
}
template <typename It>
void match_word2(It& star_end_string, It buf_end, std::string_view& val)
{
val = {};
for(auto it = star_end_string;it != buf_end;it++)
{
if (!(lut[(uint8_t)*it] & 4))
{
val = std::string_view(&*star_end_string, std::distance(star_end_string, it));
if(val.size())
{
star_end_string = --it;
return;
}else
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
}
}
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
}
template <typename It>
bool match_word(It& star_end_string, It buf_end, std::string_view& val)
{
try
{
match_word2(star_end_string, buf_end, val);
return true;
}
catch(...)
{
return false;
}
}
template <typename It>
bool match_word_with_extrasymb(It& star_end_string, It buf_end, std::string& val)
{
val = {};
for(auto it = star_end_string;it != buf_end;it++)
{
if(!isalnum(*it) && *it != '-' && *it != '_')
{
val.assign(star_end_string, it);
if(val.size())
{
star_end_string = --it;
return true;
}else
return false;
}
}
return false;
}
template <typename It>
bool match_word_til_equal_mark(It& star_end_string, It buf_end, It& word_end)
{
word_end = star_end_string;
for(auto it = star_end_string;it != buf_end;it++)
{
if(isspace(*it))
{
continue;
}else if( *it == '=' )
{
star_end_string = it;
word_end = it;
return true;
}
}
return false;
}
}
}
inline bool isspace(char c) { return detail::lut[static_cast<uint8_t>(c)] & 8; }
inline bool isdigit(char c) { return detail::lut[static_cast<uint8_t>(c)] & 1; }
void match_string2(const char*& star_end_string, const char* buf_end, std::string& val);
void match_number2(const char*& star_end_string, const char* buf_end, std::string_view& val, bool& is_float_val, bool& is_negative_val);
void match_word2(const char*& star_end_string, const char* buf_end, std::string_view& val);
}

View File

@ -28,7 +28,6 @@
#pragma once
#include "../misc_language.h"
#include "portable_storage_base.h"
#include "portable_storage_to_bin.h"
#include "portable_storage_from_bin.h"

View File

@ -28,9 +28,9 @@
#pragma once
#include "../misc_language.h"
#include "portable_storage_base.h"
#include <boost/endian/conversion.hpp>
#include <oxenc/endian.h>
#include <oxenc/variant.h>
namespace epee
{
@ -111,7 +111,7 @@ namespace epee
static_assert(std::is_integral_v<T>);
read(&v, sizeof(T));
if constexpr (sizeof(T) > 1)
boost::endian::little_to_native(v);
oxenc::little_to_host(v);
}
template <class T>

View File

@ -27,6 +27,8 @@
#pragma once
#include <string_view>
#include <charconv>
#include <oxenc/variant.h>
#include "portable_storage_base.h"
#include "parserse_base_utils.h"
#define EPEE_JSON_RECURSION_LIMIT_INTERNAL 100

View File

@ -29,9 +29,8 @@
#pragma once
#include "../pragma_comp_defs.h"
#include "../misc_language.h"
#include "portable_storage_base.h"
#include <boost/endian/conversion.hpp>
#include <oxenc/endian.h>
#include <oxenmq/variant.h>
namespace epee
@ -72,16 +71,15 @@ namespace epee
void pack_entry_to_buff(std::ostream& strm, T v)
{
if constexpr (sizeof(T) > 1)
boost::endian::native_to_little_inplace(v);
oxenc::host_to_little_inplace(v);
strm.write(reinterpret_cast<const char*>(&v), sizeof(v));
}
inline void pack_entry_to_buff(std::ostream& strm, double v)
{
static_assert(std::numeric_limits<double>::is_iec559 && sizeof(double) == 8 &&
(boost::endian::order::native == boost::endian::order::big || boost::endian::order::native == boost::endian::order::little));
static_assert(std::numeric_limits<double>::is_iec559 && sizeof(double) == 8 && (oxenc::little_endian || oxenc::big_endian));
char* buff = reinterpret_cast<char*>(&v);
if constexpr (boost::endian::order::native == boost::endian::order::big) {
if constexpr (oxenc::big_endian) {
size_t i = 8;
while (i) strm.put(buff[--i]);
} else {

View File

@ -33,7 +33,6 @@
#include <type_traits>
#include <charconv>
#include "../misc_language.h"
#include "portable_storage_base.h"
#include "parserse_base_utils.h"
#include "../warnings.h"

View File

@ -1,243 +0,0 @@
// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * 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.
// * Neither the name of the Andrey N. Sabelnikov 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 OWNER 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.
//
#ifndef _STRING_CODING_H_
#define _STRING_CODING_H_
#include <string>
namespace epee
{
namespace string_encoding
{
inline std::string convert_to_ansii(const std::wstring& str_from)
{
std::string res(str_from.begin(), str_from.end());
return res;
/*
std::string result;
std::locale loc;
for(unsigned int i= 0; i < str_from.size(); ++i)
{
result += std::use_facet<std::ctype<wchar_t> >(loc).narrow(str_from[i]);
}
return result;
*/
//return boost::lexical_cast<std::string>(str_from);
/*
std::string str_trgt;
if(!str_from.size())
return str_trgt;
int cb = ::WideCharToMultiByte( code_page, 0, str_from.data(), (__int32)str_from.size(), 0, 0, 0, 0 );
if(!cb)
return str_trgt;
str_trgt.resize(cb);
::WideCharToMultiByte( code_page, 0, str_from.data(), (int)str_from.size(),
(char*)str_trgt.data(), (int)str_trgt.size(), 0, 0);
return str_trgt;*/
}
inline std::string convert_to_ansii(const std::string& str_from)
{
return str_from;
}
inline std::wstring convert_to_unicode(const std::string& str_from)
{
std::wstring result;
std::locale loc;
for(unsigned int i= 0; i < str_from.size(); ++i)
{
result += std::use_facet<std::ctype<wchar_t> >(loc).widen(str_from[i]);
}
return result;
//return boost::lexical_cast<std::wstring>(str_from);
/*
std::wstring str_trgt;
if(!str_from.size())
return str_trgt;
int cb = ::MultiByteToWideChar( code_page, 0, str_from.data(), (int)str_from.size(), 0, 0 );
if(!cb)
return str_trgt;
str_trgt.resize(cb);
::MultiByteToWideChar( code_page, 0, str_from.data(),(int)str_from.size(),
(wchar_t*)str_trgt.data(),(int)str_trgt.size());
return str_trgt;*/
}
inline std::wstring convert_to_unicode(const std::wstring& str_from)
{
return str_from;
}
template<class target_string>
inline target_string convert_to_t(const std::wstring& str_from);
template<>
inline std::string convert_to_t<std::string>(const std::wstring& str_from)
{
return convert_to_ansii(str_from);
}
template<>
inline std::wstring convert_to_t<std::wstring>(const std::wstring& str_from)
{
return str_from;
}
template<class target_string>
inline target_string convert_to_t(const std::string& str_from);
template<>
inline std::string convert_to_t<std::string>(const std::string& str_from)
{
return str_from;
}
template<>
inline std::wstring convert_to_t<std::wstring>(const std::string& str_from)
{
return convert_to_unicode(str_from);
}
inline
std::string& base64_chars()
{
static std::string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
return chars;
}
inline
std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len) {
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while (in_len--) {
char_array_3[i++] = *(bytes_to_encode++);
if (i == 3) {
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; (i <4) ; i++)
ret += base64_chars()[char_array_4[i]];
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; (j < i + 1); j++)
ret += base64_chars()[char_array_4[j]];
while((i++ < 3))
ret += '=';
}
return ret;
}
inline
std::string base64_encode(const std::string& str)
{
return base64_encode((unsigned char const* )str.data(), str.size());
}
inline bool is_base64(unsigned char c) {
return (isalnum(c) || (c == '+') || (c == '/'));
}
inline
std::string base64_decode(std::string const& encoded_string) {
size_t in_len = encoded_string.size();
size_t i = 0;
size_t j = 0;
size_t in_ = 0;
unsigned char char_array_4[4], char_array_3[3];
std::string ret;
while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
char_array_4[i++] = encoded_string[in_]; in_++;
if (i ==4) {
for (i = 0; i <4; i++)
char_array_4[i] = (unsigned char)base64_chars().find(char_array_4[i]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (i = 0; (i < 3); i++)
ret += char_array_3[i];
i = 0;
}
}
if (i) {
for (j = i; j <4; j++)
char_array_4[j] = 0;
for (j = 0; j <4; j++)
char_array_4[j] = (unsigned char)base64_chars().find(char_array_4[j]);
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
}
return ret;
}
}
}
#endif //_STRING_CODING_H_

View File

@ -43,7 +43,6 @@
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include "storages/parserse_base_utils.h"
#include "hex.h"
#include "mlocker.h"
#include "span.h"
#include "warnings.h"
@ -60,37 +59,6 @@ using namespace std::literals;
namespace string_tools
{
//----------------------------------------------------------------------------
inline bool parse_hexstr_to_binbuff(const epee::span<const char> s, epee::span<char>& res)
{
if (s.size() != res.size() * 2)
return false;
unsigned char *dst = (unsigned char *)&res[0];
const unsigned char *src = (const unsigned char *)s.data();
for(size_t i = 0; i < s.size(); i += 2)
{
int tmp = *src++;
tmp = epee::misc_utils::parse::isx[tmp];
if (tmp == 0xff) return false;
int t2 = *src++;
t2 = epee::misc_utils::parse::isx[t2];
if (t2 == 0xff) return false;
*dst++ = (tmp << 4) | t2;
}
return true;
}
//----------------------------------------------------------------------------
inline bool parse_hexstr_to_binbuff(const std::string& s, std::string& res)
{
if (s.size() & 1)
return false;
res.resize(s.size() / 2);
epee::span<char> rspan((char*)&res[0], res.size());
return parse_hexstr_to_binbuff(epee::to_span(s), rspan);
}
//----------------------------------------------------------------------------
PUSH_WARNINGS
DISABLE_GCC_WARNING(maybe-uninitialized)
template<class XType>

View File

@ -33,7 +33,6 @@
#include <vector>
#include <string>
#include "memwipe.h"
#include "fnv1.h"
namespace epee
{
@ -105,7 +104,7 @@ namespace std
{
size_t operator()(const epee::wipeable_string &s) const
{
return epee::fnv::FNV1a(s.data(), s.size());
return hash<std::string_view>{}(s.view());
}
};
}

View File

@ -29,7 +29,6 @@
add_library(epee
buffer.cpp
connection_basic.cpp
hex.cpp
levin_base.cpp
memwipe.c
mlocker.cpp
@ -37,6 +36,7 @@ add_library(epee
net_utils_base.cpp
network_throttle.cpp
network_throttle-detail.cpp
parserse_base_utils.cpp
portable_storage.cpp
string_tools.cpp
time_helper.cpp
@ -65,6 +65,7 @@ target_link_libraries(epee
PUBLIC
easylogging
oxenmq::oxenmq
oxenc::oxenc
PRIVATE
filesystem
Boost::thread

View File

@ -38,7 +38,6 @@
#include "epee/misc_log_ex.h"
#include <thread>
#include <chrono>
#include "epee/misc_language.h"
#include "epee/pragma_comp_defs.h"
#include <iomanip>

View File

@ -40,7 +40,6 @@
#include "epee/net/net_utils_base.h"
#include "epee/misc_log_ex.h"
#include "epee/misc_language.h"
#include "epee/pragma_comp_defs.h"
#include "epee/net/abstract_tcp_server2.h"

View File

@ -0,0 +1,179 @@
#include "epee/storages/parserse_base_utils.h"
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "serialization"
#include <algorithm>
#include <string>
#include <string_view>
#include <oxenc/hex.h>
#include "epee/misc_log_ex.h"
namespace epee::misc_utils::parse {
/*
\b Backspace (ascii code 08)
\f Form feed (ascii code 0C)
\n New line
\r Carriage return
\t Tab
\v Vertical tab
\' Apostrophe or single quote
\" Double quote
\\ Backslash character
*/
void match_string2(const char*& star_end_string, const char* buf_end, std::string& val)
{
bool escape_mode = false;
auto it = star_end_string;
++it;
auto fi = it;
while (fi != buf_end && ((detail::lut[(uint8_t)*fi] & 32)) == 0)
++fi;
val.assign(it, fi);
val.reserve(std::distance(star_end_string, buf_end));
it = fi;
for(;it != buf_end;it++)
{
if(escape_mode/*prev_ch == '\\'*/)
{
switch(*it)
{
case 'b': //Backspace (ascii code 08)
val.push_back(0x08);break;
case 'f': //Form feed (ascii code 0C)
val.push_back(0x0C);break;
case 'n': //New line
val.push_back('\n');break;
case 'r': //Carriage return
val.push_back('\r');break;
case 't': //Tab
val.push_back('\t');break;
case 'v': //Vertical tab
val.push_back('\v');break;
case '\'': //Apostrophe or single quote
val.push_back('\'');break;
case '"': //Double quote
val.push_back('"');break;
case '\\': //Backslash character
val.push_back('\\');break;
case '/': //Slash character
val.push_back('/');break;
case 'u': //Unicode code point
if (buf_end - it < 4)
{
ASSERT_MES_AND_THROW("Invalid Unicode escape sequence");
}
else
{
uint32_t dst = 0;
for (int i = 0; i < 4; ++i)
{
const auto c = *++it;
CHECK_AND_ASSERT_THROW_MES(oxenc::is_hex_digit(c), "Bad Unicode encoding: " + std::to_string(c));
dst = dst << 4 | oxenc::from_hex_digit(c);
}
// encode as UTF-8
if (dst <= 0x7f)
{
val.push_back(dst);
}
else if (dst <= 0x7ff)
{
val.push_back(0xc0 | (dst >> 6));
val.push_back(0x80 | (dst & 0x3f));
}
else if (dst <= 0xffff)
{
val.push_back(0xe0 | (dst >> 12));
val.push_back(0x80 | ((dst >> 6) & 0x3f));
val.push_back(0x80 | (dst & 0x3f));
}
else
{
ASSERT_MES_AND_THROW("Unicode code point is out or range");
}
}
break;
default:
val.push_back(*it);
LOG_PRINT_L0("Unknown escape sequence :\"\\" << *it << "\"");
}
escape_mode = false;
}else if(*it == '"')
{
star_end_string = it;
return;
}else if(*it == '\\')
{
escape_mode = true;
}
else
{
val.push_back(*it);
}
}
ASSERT_MES_AND_THROW("Failed to match string in json entry: " << std::string(star_end_string, buf_end));
}
// The only conclusive thing that can be said about this function is that it does indeed
// closely match a "number 2". 💩
void match_number2(const char*& star_end_string, const char* buf_end, std::string_view& val, bool& is_float_val, bool& is_negative_val)
{
val = {};
uint8_t float_flag = 0;
is_negative_val = false;
is_float_val = false;
size_t chars = 0;
auto it = star_end_string;
if (it != buf_end && *it == '-')
{
is_negative_val = true;
++chars;
++it;
}
for(;it != buf_end;it++)
{
const uint8_t flags = detail::lut[(uint8_t)*it];
if (flags & 16)
{
float_flag |= flags;
++chars;
}
else
{
val = std::string_view(&*star_end_string, chars);
if(val.size())
{
star_end_string = --it;
is_float_val = !!(float_flag & 2);
return;
}
else
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
}
}
ASSERT_MES_AND_THROW("wrong number in json entry: " << std::string(star_end_string, buf_end));
}
void match_word2(const char*& star_end_string, const char* buf_end, std::string_view& val)
{
val = {};
for(auto it = star_end_string;it != buf_end;it++)
{
if (!(detail::lut[(uint8_t)*it] & 4))
{
val = std::string_view(&*star_end_string, std::distance(star_end_string, it));
if(val.size())
{
star_end_string = --it;
return;
}else
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
}
}
ASSERT_MES_AND_THROW("failed to match word number in json entry: " << std::string(star_end_string, buf_end));
}
} // namespace epee::misc_utils::parse

View File

@ -229,7 +229,6 @@ namespace tests
{
LOG_PRINT_L0("on_command_2: id "<< arg.example_id_data);
rsp.example_id_data = arg.example_id_data;
//misc_utils::sleep_no_w(6000);
return true;
}
//----------------------------------------------------------------------------------
@ -266,7 +265,7 @@ namespace tests
std::thread th2{[&srv2] { srv2.run(); }};
LOG_PRINT_L0("Initialized servers, waiting for worker threads started...");
misc_utils::sleep_no_w(1000);
std::this_thread::sleep_for(1s);
LOG_PRINT_L0("Connecting to each other...");
@ -369,7 +368,7 @@ namespace tests
std::thread thmain2{ [&srv2] { srv2.run(); } };
LOG_PRINT_L0("Initalized servers, waiting for worker threads started...");
misc_utils::sleep_no_w(1000);
std::this_thread::sleep_for(1s);
LOG_PRINT_L0("Connecting to each other...");

View File

@ -1,7 +1,6 @@
#include "include_base_utils.h"
#include "storages/storage_tests.h"
#include "misc/test_math.h"
#include "storages/portable_storages_test.h"
#include "net/test_net.h"
@ -39,13 +38,6 @@ int main(int argc, char* argv[])
}
}else if(string_tools::have_in_command_line(start_params, std::string("/run_unit_tests")))
{
if(!tests::test_median())
{
LOG_ERROR("median test failed");
return 1;
}
if(!tests::test_storages(tests_data_path))
{
LOG_ERROR("storage test failed");

View File

@ -33,60 +33,44 @@
# ...except for FreeBSD, because FreeBSD is a special case that doesn't play well with
# others.
set(DEFAULT_WITH_MINIUPNPC ON)
if(ANDROID OR IOS)
set(DEFAULT_WITH_MINIUPNPC OFF)
endif()
option(WITH_MINIUPNPC "Enable miniupnpc support for IGD NAT hole punching" ${DEFAULT_WITH_MINIUPNPC})
if(NOT STATIC AND NOT BUILD_STATIC_DEPS)
find_package(PkgConfig REQUIRED)
if(WITH_MINIUPNPC)
pkg_check_modules(MINIUPNPC miniupnpc>=2.1 IMPORTED_TARGET)
endif()
pkg_check_modules(OXENMQ liboxenmq>=1.2.7 IMPORTED_TARGET)
endif()
if(NOT WITH_MINIUPNPC)
message(STATUS "miniupnpc support disabled")
target_compile_definitions(miniupnpc INTERFACE WITHOUT_MINIUPNPC)
elseif(MINIUPNPC_FOUND)
message(STATUS "Found miniupnpc")
target_link_libraries(miniupnpc INTERFACE PkgConfig::MINIUPNPC)
else()
message(STATUS "Using in-tree miniupnpc")
add_subdirectory(miniupnp/miniupnpc)
if(MSVC)
target_compile_options(libminiupnpc-static PRIVATE -wd4244 -wd4267)
macro(system_or_submodule BIGNAME smallname pkgconf subdir)
option(FORCE_${BIGNAME}_SUBMODULE "force using ${smallname} submodule" OFF)
if(NOT STATIC AND NOT FORCE_${BIGNAME}_SUBMODULE)
pkg_check_modules(${BIGNAME} ${pkgconf} IMPORTED_TARGET)
endif()
if(${BIGNAME}_FOUND)
add_library(${smallname} INTERFACE)
if(NOT TARGET PkgConfig::${BIGNAME} AND CMAKE_VERSION VERSION_LESS "3.21")
# Work around cmake bug 22180 (PkgConfig::THING not set if no flags needed)
else()
target_link_libraries(${smallname} INTERFACE PkgConfig::${BIGNAME})
endif()
message(STATUS "Found system ${smallname} ${${BIGNAME}_VERSION}")
else()
target_compile_options(libminiupnpc-static PRIVATE -Wno-undef -Wno-unused-result -Wno-unused-value)
message(STATUS "using ${smallname} submodule")
add_subdirectory(${subdir})
endif()
if(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
target_compile_definitions(libminiupnpc-static PRIVATE _NETBSD_SOURCE)
if(NOT TARGET ${smallname}::${smallname})
add_library(${smallname}::${smallname} ALIAS ${smallname})
endif()
endmacro()
target_link_libraries(miniupnpc INTERFACE libminiupnpc-static)
endif()
system_or_submodule(OXENC oxenc liboxenc>=1.0.3 oxen-encoding)
system_or_submodule(OXENMQ oxenmq liboxenmq>=1.2.12 oxen-mq)
system_or_submodule(FMT fmt fmt>=8.0.0 fmt)
if(NOT OXENMQ_FOUND)
message(STATUS "Using in-tree oxenmq")
add_subdirectory(loki-mq)
else()
add_library(oxenmq INTERFACE)
target_link_libraries(oxenmq INTERFACE PkgConfig::OXENMQ)
add_library(oxenmq::oxenmq ALIAS oxenmq)
message(STATUS "Found liboxenmq ${OXENMQ_VERSION}")
endif()
add_subdirectory(oxenc)
system_or_submodule(OXENC oxenc liboxenc>=1.0.3 oxen-encoding)
system_or_submodule(OXENMQ oxenmq liboxenmq>=1.2.12 oxen-mq)
system_or_submodule(FMT fmt fmt>=8.0.0 fmt)
add_subdirectory(db_drivers)
add_subdirectory(easylogging++ easyloggingpp)
add_subdirectory(randomx EXCLUDE_FROM_ALL)
add_subdirectory(date EXCLUDE_FROM_ALL)
add_subdirectory(fmt)
set(JSON_BuildTests OFF CACHE INTERNAL "")
set(JSON_MultipleHeaders ON CACHE BOOL "") # Allows multi-header nlohmann use
@ -152,6 +136,21 @@ target_include_directories(cpr PUBLIC cpr/include)
target_compile_definitions(cpr PUBLIC CPR_CURL_NOSIGNAL)
add_library(cpr::cpr ALIAS cpr)
file(READ cpr/CMakeLists.txt cpr_cmake_head LIMIT 1000)
if(cpr_cmake_head MATCHES "project\\(cpr VERSION ([0-9]+)\.([0-9]+)\.([0-9]+) LANGUAGES CXX\\)")
set(cpr_VERSION_MAJOR ${CMAKE_MATCH_1})
set(cpr_VERSION_MINOR ${CMAKE_MATCH_2})
set(cpr_VERSION_PATCH ${CMAKE_MATCH_3})
set(cpr_VERSION "${cpr_VERSION_MAJOR}.${cpr_VERSION_MINOR}.${cpr_VERSION_PATCH}")
set(cpr_VERSION_NUM "(${cpr_VERSION_MAJOR} * 0x10000 + ${cpr_VERSION_MINOR} * 0x100 + ${cpr_VERSION_PATCH})")
configure_file(cpr/cmake/cprver.h.in "${CMAKE_CURRENT_BINARY_DIR}/cpr_generated_includes/cpr/cprver.h")
target_include_directories(cpr PUBLIC "${CMAKE_CURRENT_BINARY_DIR}/cpr_generated_includes")
else()
message(FATAL_ERROR "Could not identify cpr submodule version!")
endif()
# Hack around SQLiteCpp's attempts to locate sqlite3 because we *don't* want to link against the
# system one, but don't download and build the embedded one until build time. Thankfully it
# actually links against the SQLite::SQLite3 cmake target if it already exists, so all we have to do

1
external/loki-mq vendored

@ -1 +0,0 @@
Subproject commit e1b1a84c4bddc344eb99182ef5d667bcfaf02ca1

1
external/miniupnp vendored

@ -1 +0,0 @@
Subproject commit 81029a860baf1f727903e5b85307903b3f40cbc8

1
external/oxen-encoding vendored Submodule

@ -0,0 +1 @@
Subproject commit a0912ab4bf3b5e83b42715eff6f632c8912b21e4

1
external/oxen-mq vendored Submodule

@ -0,0 +1 @@
Subproject commit 5c72a57eca120750ecf557ce5a668fb38242956b

View File

@ -47,10 +47,6 @@ function (oxen_add_executable target binary)
set_property(GLOBAL PROPERTY oxen_executable_targets "${exec_tgt}")
endfunction ()
include(Version)
add_library(version ${CMAKE_BINARY_DIR}/version.cpp)
add_dependencies(version genversion)
add_subdirectory(common)
add_subdirectory(crypto)
add_subdirectory(ringct)
@ -71,6 +67,7 @@ add_subdirectory(p2p)
add_subdirectory(daemonizer)
add_subdirectory(daemon)
add_subdirectory(simplewallet)
add_subdirectory(sqlitedb)
add_subdirectory(gen_multisig)
add_subdirectory(blockchain_utilities)
@ -92,3 +89,38 @@ endif()
add_subdirectory(device)
add_subdirectory(device_trezor)
if(OXEN_VERSIONTAG)
set(VERSIONTAG "${OXEN_VERSIONTAG}")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
else()
set(GIT_INDEX_FILE "${PROJECT_SOURCE_DIR}/.git/index")
find_package(Git)
if(EXISTS ${GIT_INDEX_FILE} AND ( GIT_FOUND OR Git_FOUND) )
message(STATUS "Found Git: ${GIT_EXECUTABLE}")
set(genversion_args "-DGIT=${GIT_EXECUTABLE}")
foreach(v oxen_VERSION oxen_VERSION_MAJOR oxen_VERSION_MINOR oxen_VERSION_PATCH OXEN_RELEASE_CODENAME OXEN_RELEASE_SUFFIX)
list(APPEND genversion_args "-D${v}=${${v}}")
endforeach()
add_custom_command(
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/version.cpp"
COMMAND
"${CMAKE_COMMAND}"
${genversion_args}
"-DSRC=${CMAKE_CURRENT_SOURCE_DIR}/version.cpp.in"
"-DDEST=${CMAKE_CURRENT_BINARY_DIR}/version.cpp"
"-P" "${PROJECT_SOURCE_DIR}/cmake/GenVersion.cmake"
DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/version.cpp.in"
"${GIT_INDEX_FILE}")
else()
message(STATUS "Git was not found! Setting version tag to to nogit")
set(VERSIONTAG "nogit")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")
endif()
endif()
add_library(version "${CMAKE_CURRENT_BINARY_DIR}/version.cpp")

View File

@ -30,9 +30,12 @@
add_library(blockchain_db
blockchain_db.cpp
lmdb/db_lmdb.cpp
sqlite/db_sqlite.cpp
)
target_link_libraries(blockchain_db
PUBLIC
sqlitedb
PRIVATE
common
ringct

View File

@ -75,7 +75,7 @@ void BlockchainDB::pop_block()
pop_block(blk, txs);
}
void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& txp, const crypto::hash* tx_hash_ptr, const crypto::hash* tx_prunable_hash_ptr)
void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair<transaction, std::string>& txp, const crypto::hash* tx_hash_ptr, const crypto::hash* tx_prunable_hash_ptr)
{
const transaction &tx = txp.first;
@ -172,12 +172,12 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair
add_tx_amount_output_indices(tx_id, amount_output_indices);
}
uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
uint64_t BlockchainDB::add_block( const std::pair<block, std::string>& blck
, size_t block_weight
, uint64_t long_term_block_weight
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, const std::vector<std::pair<transaction, blobdata>>& txs
, const std::vector<std::pair<transaction, std::string>>& txs
)
{
const block &blk = blck.first;
@ -203,7 +203,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
int tx_i = 0;
crypto::hash tx_hash = crypto::null_hash;
for (const std::pair<transaction, blobdata>& tx : txs)
for (const std::pair<transaction, std::string>& tx : txs)
{
tx_hash = blk.tx_hashes[tx_i];
add_transaction(blk_hash, tx, &tx_hash);
@ -274,7 +274,7 @@ block BlockchainDB::get_block(const crypto::hash& h) const
bool BlockchainDB::get_tx(const crypto::hash& h, cryptonote::transaction &tx) const
{
blobdata bd;
std::string bd;
if (!get_tx_blob(h, bd))
return false;
if (!parse_and_validate_tx_from_blob(bd, tx))
@ -285,11 +285,13 @@ bool BlockchainDB::get_tx(const crypto::hash& h, cryptonote::transaction &tx) co
bool BlockchainDB::get_pruned_tx(const crypto::hash& h, cryptonote::transaction &tx) const
{
blobdata bd;
std::string bd;
if (!get_pruned_tx_blob(h, bd))
return false;
if (!parse_and_validate_tx_base_from_blob(bd, tx))
{
throw DB_ERROR("Failed to parse transaction base from blob retrieved from the db");
}
return true;
}
@ -397,9 +399,9 @@ uint64_t BlockchainDB::get_tx_block_height(const crypto::hash &h) const
return result;
}
bool BlockchainDB::get_alt_block_header(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::block_header *header, cryptonote::blobdata *checkpoint) const
bool BlockchainDB::get_alt_block_header(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::block_header *header, std::string *checkpoint) const
{
cryptonote::blobdata blob;
std::string blob;
if (!get_alt_block(blkid, data, &blob, checkpoint))
{
throw BLOCK_DNE("Alt-block with hash " + tools::type_to_hex(blkid) + " not found in db");
@ -430,8 +432,8 @@ void BlockchainDB::fill_timestamps_and_difficulties_for_pow(cryptonote::network_
return;
uint64_t const top_block_height = chain_height - 1;
bool const before_hf16 = !is_hard_fork_at_least(nettype, network_version_16_pulse, chain_height);
uint64_t const block_count = DIFFICULTY_BLOCKS_COUNT(before_hf16);
bool const before_hf16 = !is_hard_fork_at_least(nettype, hf::hf16_pulse, chain_height);
uint64_t const block_count = old::DIFFICULTY_BLOCKS_COUNT(before_hf16);
timestamps.reserve(block_count);
difficulties.reserve(block_count);

View File

@ -36,7 +36,6 @@
#include "common/command_line.h"
#include "common/fs.h"
#include "crypto/hash.h"
#include "cryptonote_basic/blobdatatype.h"
#include "cryptonote_basic/cryptonote_basic.h"
#include "cryptonote_basic/difficulty.h"
@ -414,7 +413,7 @@ private:
* @param tx_prunable_hash the hash of the prunable part of the transaction
* @return the transaction ID
*/
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) = 0;
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, std::string>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) = 0;
/**
* @brief remove data about a transaction
@ -542,7 +541,7 @@ protected:
* @param tx_hash_ptr the hash of the transaction, if already calculated
* @param tx_prunable_hash_ptr the hash of the prunable part of the transaction, if already calculated
*/
void add_transaction(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& tx, const crypto::hash* tx_hash_ptr = NULL, const crypto::hash* tx_prunable_hash_ptr = NULL);
void add_transaction(const crypto::hash& blk_hash, const std::pair<transaction, std::string>& tx, const crypto::hash* tx_hash_ptr = NULL, const crypto::hash* tx_prunable_hash_ptr = NULL);
mutable std::chrono::nanoseconds time_tx_exists = 0ns; //!< a performance metric
std::chrono::nanoseconds time_commit1 = 0ns; //!< a performance metric
@ -815,12 +814,12 @@ public:
*
* @return the height of the chain post-addition
*/
virtual uint64_t add_block( const std::pair<block, blobdata>& blk
virtual uint64_t add_block( const std::pair<block, std::string>& blk
, size_t block_weight
, uint64_t long_term_block_weight
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, const std::vector<std::pair<transaction, blobdata>>& txs
, const std::vector<std::pair<transaction, std::string>>& txs
);
virtual void update_block_checkpoint(checkpoint_t const &checkpoint) = 0;
@ -854,7 +853,7 @@ public:
*
* @return the block requested
*/
virtual cryptonote::blobdata get_block_blob(const crypto::hash& h) const = 0;
virtual std::string get_block_blob(const crypto::hash& h) const = 0;
/**
* @brief fetches the block with the given hash
@ -922,7 +921,7 @@ public:
*
* @return the block blob
*/
virtual cryptonote::blobdata get_block_blob_from_height(uint64_t height) const = 0;
virtual std::string get_block_blob_from_height(uint64_t height) const = 0;
/**
* @brief fetch a block by height
@ -1266,7 +1265,7 @@ public:
*
* @return true iff the transaction was found
*/
virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const = 0;
virtual bool get_tx_blob(const crypto::hash& h, std::string &tx) const = 0;
/**
* @brief fetches the pruned transaction blob with the given hash
@ -1280,7 +1279,7 @@ public:
*
* @return true iff the transaction was found
*/
virtual bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const = 0;
virtual bool get_pruned_tx_blob(const crypto::hash& h, std::string &tx) const = 0;
/**
* @brief fetches a number of pruned transaction blob from the given hash, in canonical blockchain order
@ -1296,7 +1295,7 @@ public:
*
* @return true iff the transactions were found
*/
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const = 0;
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<std::string> &bd) const = 0;
/**
* @brief fetches the prunable transaction blob with the given hash
@ -1311,7 +1310,7 @@ public:
*
* @return true iff the transaction was found and we have its prunable data
*/
virtual bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const = 0;
virtual bool get_prunable_tx_blob(const crypto::hash& h, std::string &tx) const = 0;
/**
* @brief fetches the prunable transaction hash
@ -1512,7 +1511,7 @@ public:
*
* @param details the details of the transaction to add
*/
virtual void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t& details) = 0;
virtual void add_txpool_tx(const crypto::hash &txid, const std::string &blob, const txpool_tx_meta_t& details) = 0;
/**
* @brief update a txpool transaction's metadata
@ -1557,7 +1556,7 @@ public:
*
* @return true if the txid was in the txpool, false otherwise
*/
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const = 0;
virtual bool get_txpool_tx_blob(const crypto::hash& txid, std::string &bd) const = 0;
/**
* @brief get a txpool transaction's blob
@ -1566,7 +1565,7 @@ public:
*
* @return the blob for that transaction
*/
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const = 0;
virtual std::string get_txpool_tx_blob(const crypto::hash& txid) const = 0;
/**
* @brief prune output data for the given amount
@ -1621,7 +1620,7 @@ public:
* @param: data: the metadata for the block
* @param: blob: the block's blob
*/
virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob, const cryptonote::blobdata *checkpoint) = 0;
virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const std::string &blob, const std::string *checkpoint) = 0;
/**
* @brief get an alternative block by hash
@ -1632,7 +1631,7 @@ public:
*
* @return true if the block was found in the alternative blocks list, false otherwise
*/
virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob, cryptonote::blobdata *checkpoint) const = 0;
virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, std::string *blob, std::string *checkpoint) const = 0;
/**
* @brief get the block header from the alternative block db
@ -1644,7 +1643,7 @@ public:
*
* @return true if the block was found in the alternative blocks list, false otherwise
*/
bool get_alt_block_header(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::block_header *header, cryptonote::blobdata *checkpoint) const;
bool get_alt_block_header(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::block_header *header, std::string *checkpoint) const;
/**
* @brief remove an alternative block
@ -1676,7 +1675,7 @@ public:
*
* @return false if the function returns false for any transaction, otherwise true
*/
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = true) const = 0;
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const std::string*)>, bool include_blob = false, bool include_unrelayed_txes = true) const = 0;
/**
* @brief runs a function over all key images stored
@ -1768,7 +1767,7 @@ public:
*
* @return false if the function returns false for any output, otherwise true
*/
virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *block_blob, const cryptonote::blobdata *checkpoint_blob)> f, bool include_blob = false) const = 0;
virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const std::string *block_blob, const std::string *checkpoint_blob)> f, bool include_blob = false) const = 0;
/**
* @brief return a histogram of outputs on the blockchain

View File

@ -29,8 +29,8 @@
#include "db_lmdb.h"
#include <boost/circular_buffer.hpp>
#include <boost/endian/conversion.hpp>
#include <chrono>
#include <oxenc/endian.h>
#include <memory>
#include <cstring>
#include <type_traits>
@ -42,6 +42,7 @@
#include "common/file.h"
#include "common/pruning.h"
#include "common/hex.h"
#include "common/median.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "crypto/crypto.h"
#include "ringct/rctOps.h"
@ -56,7 +57,6 @@
using namespace crypto;
using namespace boost::endian;
enum struct lmdb_version
{
@ -115,9 +115,9 @@ private:
};
template<>
struct MDB_val_copy<cryptonote::blobdata>: public MDB_val
struct MDB_val_copy<std::string>: public MDB_val
{
MDB_val_copy(const cryptonote::blobdata &bd) :
MDB_val_copy(const std::string &bd) :
data(new char[bd.size()])
{
memcpy(data.get(), bd.data(), bd.size());
@ -880,7 +880,7 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
CURSOR(block_info)
// this call to mdb_cursor_put will change height()
cryptonote::blobdata block_blob(block_to_blob(blk));
std::string block_blob(block_to_blob(blk));
MDB_val_sized(blob, block_blob);
result = mdb_cursor_put(m_cur_blocks, &key, &blob, MDB_APPEND);
if (result)
@ -894,12 +894,12 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
bi.bi_diff = cumulative_difficulty;
bi.bi_hash = blk_hash;
bi.bi_cum_rct = num_rct_outs;
if (blk.major_version >= 4 && m_height > 0)
if (m_height > 0)
{
uint64_t last_height = m_height-1;
MDB_val_set(h, last_height);
if ((result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &h, MDB_GET_BOTH)))
throw1(BLOCK_DNE(lmdb_error("Failed to get block info: ", result).c_str()));
throw1(BLOCK_DNE(lmdb_error("Failed to get parent block info: ", result).c_str()));
const mdb_block_info *bi_prev = (const mdb_block_info*)h.mv_data;
bi.bi_cum_rct += bi_prev->bi_cum_rct;
}
@ -957,7 +957,7 @@ void BlockchainLMDB::remove_block()
throw1(DB_ERROR(lmdb_error("Failed to add removal of block info to db transaction: ", result).c_str()));
}
uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& txp, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash)
uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, std::string>& txp, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -997,7 +997,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add tx data to db transaction: ", result).c_str()));
const cryptonote::blobdata &blob = txp.second;
const std::string &blob = txp.second;
MDB_val_sized(blobval, blob);
unsigned int unprunable_size = tx.unprunable_size;
@ -1417,11 +1417,11 @@ void BlockchainLMDB::open(const fs::path& filename, cryptonote::network_type net
// check for existing LMDB files in base directory
auto old_files = filename.parent_path();
if (fs::exists(old_files / CRYPTONOTE_BLOCKCHAINDATA_FILENAME)
|| fs::exists(old_files / CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME))
if (fs::exists(old_files / BLOCKCHAINDATA_FILENAME)
|| fs::exists(old_files / BLOCKCHAINDATA_LOCK_FILENAME))
{
LOG_PRINT_L0("Found existing LMDB files in " << old_files.u8string());
LOG_PRINT_L0("Move " << CRYPTONOTE_BLOCKCHAINDATA_FILENAME << " and/or " << CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME << " to " << filename << ", or delete them, and then restart");
LOG_PRINT_L0("Move " << BLOCKCHAINDATA_FILENAME << " and/or " << BLOCKCHAINDATA_LOCK_FILENAME << " to " << filename << ", or delete them, and then restart");
throw DB_ERROR("Database could not be opened");
}
@ -1729,14 +1729,14 @@ std::vector<fs::path> BlockchainLMDB::get_filenames() const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
std::vector<fs::path> paths;
paths.push_back(m_folder / CRYPTONOTE_BLOCKCHAINDATA_FILENAME);
paths.push_back(m_folder / CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME);
paths.push_back(m_folder / BLOCKCHAINDATA_FILENAME);
paths.push_back(m_folder / BLOCKCHAINDATA_LOCK_FILENAME);
return paths;
}
bool BlockchainLMDB::remove_data_file(const fs::path& folder) const
{
auto filename = folder / CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
auto filename = folder / BLOCKCHAINDATA_FILENAME;
try
{
fs::remove(filename);
@ -1822,7 +1822,7 @@ void BlockchainLMDB::unlock()
auto_txn.commit(); \
} while(0)
void BlockchainLMDB::add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t &meta)
void BlockchainLMDB::add_txpool_tx(const crypto::hash &txid, const std::string &blob, const txpool_tx_meta_t &meta)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -1983,7 +1983,7 @@ bool BlockchainLMDB::get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta
return true;
}
bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const
bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, std::string &bd) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -2003,9 +2003,9 @@ bool BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid, cryptonote::bl
return true;
}
cryptonote::blobdata BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid) const
std::string BlockchainLMDB::get_txpool_tx_blob(const crypto::hash& txid) const
{
cryptonote::blobdata bd;
std::string bd;
if (!get_txpool_tx_blob(txid, bd))
throw1(DB_ERROR("Tx not found in txpool: "));
return bd;
@ -2049,10 +2049,10 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
const uint32_t log_stripes = tools::get_pruning_log_stripes(pruning_seed);
if (log_stripes && log_stripes != CRYPTONOTE_PRUNING_LOG_STRIPES)
if (log_stripes && log_stripes != PRUNING_LOG_STRIPES)
throw0(DB_ERROR("Pruning seed not in range"));
pruning_seed = tools::get_pruning_stripe(pruning_seed);
if (pruning_seed > (1ul << CRYPTONOTE_PRUNING_LOG_STRIPES))
if (pruning_seed > (1ul << PRUNING_LOG_STRIPES))
throw0(DB_ERROR("Pruning seed not in range"));
check_open();
@ -2086,7 +2086,7 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
}
if (pruning_seed == 0)
pruning_seed = tools::get_random_stripe();
pruning_seed = tools::make_pruning_seed(pruning_seed, CRYPTONOTE_PRUNING_LOG_STRIPES);
pruning_seed = tools::make_pruning_seed(pruning_seed, PRUNING_LOG_STRIPES);
v.mv_data = &pruning_seed;
v.mv_size = sizeof(pruning_seed);
result = mdb_put(txn, m_properties, &k, &v, 0);
@ -2104,9 +2104,9 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
pruning_seed = tools::get_pruning_stripe(data);
if (tools::get_pruning_stripe(data) != pruning_seed)
throw0(DB_ERROR("Blockchain already pruned with different seed"));
if (tools::get_pruning_log_stripes(data) != CRYPTONOTE_PRUNING_LOG_STRIPES)
if (tools::get_pruning_log_stripes(data) != PRUNING_LOG_STRIPES)
throw0(DB_ERROR("Blockchain already pruned with different base"));
pruning_seed = tools::make_pruning_seed(pruning_seed, CRYPTONOTE_PRUNING_LOG_STRIPES);
pruning_seed = tools::make_pruning_seed(pruning_seed, PRUNING_LOG_STRIPES);
prune_tip_table = (mode == prune_mode_update);
}
else
@ -2145,7 +2145,7 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
uint64_t block_height;
memcpy(&block_height, v.mv_data, sizeof(block_height));
if (block_height + CRYPTONOTE_PRUNING_TIP_BLOCKS < blockchain_height)
if (block_height + PRUNING_TIP_BLOCKS < blockchain_height)
{
++n_total_records;
if (!tools::has_unpruned_block(block_height, blockchain_height, pruning_seed) && !is_v1_tx(c_txs_pruned, &k))
@ -2213,7 +2213,7 @@ bool BlockchainLMDB::prune_worker(int mode, uint32_t pruning_seed)
txindex ti;
memcpy(&ti, v.mv_data, sizeof(ti));
const uint64_t block_height = ti.data.block_id;
if (block_height + CRYPTONOTE_PRUNING_TIP_BLOCKS >= blockchain_height)
if (block_height + PRUNING_TIP_BLOCKS >= blockchain_height)
{
MDB_val_set(kp, ti.data.tx_id);
MDB_val_set(vp, block_height);
@ -2340,7 +2340,7 @@ bool BlockchainLMDB::check_pruning()
return prune_worker(prune_mode_check, 0);
}
bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob, bool include_unrelayed_txes) const
bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const std::string*)> f, bool include_blob, bool include_unrelayed_txes) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -2367,8 +2367,8 @@ bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&,
if (!include_unrelayed_txes && meta.do_not_relay)
// Skipping that tx
continue;
const cryptonote::blobdata *passed_bd = NULL;
cryptonote::blobdata bd;
const std::string *passed_bd = NULL;
std::string bd;
if (include_blob)
{
MDB_val b;
@ -2407,18 +2407,18 @@ static_assert(sizeof(blob_header) == 8, "blob_header layout is unexpected, possi
static blob_header write_little_endian_blob_header(blob_type type, uint32_t size)
{
blob_header result = {type, size};
native_to_little_inplace(result.size);
oxenc::host_to_little_inplace(result.size);
return result;
}
static blob_header native_endian_blob_header(const blob_header *header)
static blob_header host_endian_blob_header(const blob_header *header)
{
blob_header result = {header->type, header->size};
little_to_native_inplace(result.size);
oxenc::little_to_host_inplace(result.size);
return result;
}
static bool read_alt_block_data_from_mdb_val(MDB_val const v, alt_block_data_t *data, cryptonote::blobdata *block, cryptonote::blobdata *checkpoint)
static bool read_alt_block_data_from_mdb_val(MDB_val const v, alt_block_data_t *data, std::string *block, std::string *checkpoint)
{
size_t const conservative_min_size = sizeof(*data) + sizeof(blob_header);
if (v.mv_size < conservative_min_size)
@ -2433,7 +2433,7 @@ static bool read_alt_block_data_from_mdb_val(MDB_val const v, alt_block_data_t *
src = reinterpret_cast<const char *>(alt_data + 1);
while (src < end)
{
blob_header header = native_endian_blob_header(reinterpret_cast<const blob_header *>(src));
blob_header header = host_endian_blob_header(reinterpret_cast<const blob_header *>(src));
src += sizeof(header);
if (header.type == blob_type::block)
{
@ -2453,7 +2453,7 @@ static bool read_alt_block_data_from_mdb_val(MDB_val const v, alt_block_data_t *
return true;
}
bool BlockchainLMDB::for_all_alt_blocks(std::function<bool(const crypto::hash&, const alt_block_data_t&, const cryptonote::blobdata*, const cryptonote::blobdata *)> f, bool include_blob) const
bool BlockchainLMDB::for_all_alt_blocks(std::function<bool(const crypto::hash&, const alt_block_data_t&, const std::string*, const std::string *)> f, bool include_blob) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -2476,12 +2476,12 @@ bool BlockchainLMDB::for_all_alt_blocks(std::function<bool(const crypto::hash&,
throw0(DB_ERROR(lmdb_error("Failed to enumerate alt blocks: ", result).c_str()));
const crypto::hash &blkid = *(const crypto::hash*)k.mv_data;
cryptonote::blobdata block;
cryptonote::blobdata checkpoint;
std::string block;
std::string checkpoint;
alt_block_data_t data = {};
cryptonote::blobdata *block_ptr = (include_blob) ? &block : nullptr;
cryptonote::blobdata *checkpoint_ptr = (include_blob) ? &checkpoint : nullptr;
std::string *block_ptr = (include_blob) ? &block : nullptr;
std::string *checkpoint_ptr = (include_blob) ? &checkpoint : nullptr;
if (!read_alt_block_data_from_mdb_val(v, &data, block_ptr, checkpoint_ptr))
throw0(DB_ERROR("Record size is less than expected"));
@ -2528,17 +2528,18 @@ bool BlockchainLMDB::block_exists(const crypto::hash& h, uint64_t *height) const
template <typename T,
std::enable_if_t<std::is_same_v<T, cryptonote::block> ||
std::is_same_v<T, cryptonote::block_header> ||
std::is_same_v<T, cryptonote::blobdata>, int>>
std::is_same_v<T, std::string>, int>>
T BlockchainLMDB::get_and_convert_block_blob_from_height(uint64_t height) const
{
// NOTE: Avoid any intermediary functions like taking a blob, then converting
// to block which incurs a copy into blobdata then conversion, and prefer
// to block which incurs a copy into std::string then conversion, and prefer
// converting directly from the data initially fetched.
// Avoid casting block to block_header so we only have to deserialize the
// header, not the full-block (of which a good chunk is thrown away because we
// only want the header).
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX_RDONLY();
@ -2565,7 +2566,7 @@ T BlockchainLMDB::get_and_convert_block_blob_from_height(uint64_t height) const
serialization::binary_string_unarchiver ba{blob};
serialization::value(ba, result);
}
else if constexpr (std::is_same_v<T, cryptonote::blobdata>)
else if constexpr (std::is_same_v<T, std::string>)
{
result = blob;
}
@ -2580,7 +2581,7 @@ block BlockchainLMDB::get_block_from_height(uint64_t height) const
return result;
}
cryptonote::blobdata BlockchainLMDB::get_block_blob(const crypto::hash& h) const
std::string BlockchainLMDB::get_block_blob(const crypto::hash& h) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -2614,10 +2615,10 @@ block_header BlockchainLMDB::get_block_header_from_height(uint64_t height) const
return result;
}
cryptonote::blobdata BlockchainLMDB::get_block_blob_from_height(uint64_t height) const
std::string BlockchainLMDB::get_block_blob_from_height(uint64_t height) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
cryptonote::blobdata result = get_and_convert_block_blob_from_height<blobdata>(height);
std::string result = get_and_convert_block_blob_from_height<std::string>(height);
return result;
}
@ -3134,7 +3135,7 @@ uint64_t BlockchainLMDB::get_tx_unlock_time(const crypto::hash& h) const
return ret;
}
bool BlockchainLMDB::get_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd) const
bool BlockchainLMDB::get_tx_blob(const crypto::hash& h, std::string &bd) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -3169,7 +3170,7 @@ bool BlockchainLMDB::get_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd
return true;
}
bool BlockchainLMDB::get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd) const
bool BlockchainLMDB::get_pruned_tx_blob(const crypto::hash& h, std::string &bd) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -3197,7 +3198,7 @@ bool BlockchainLMDB::get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobd
return true;
}
bool BlockchainLMDB::get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const
bool BlockchainLMDB::get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<std::string> &bd) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -3237,7 +3238,7 @@ bool BlockchainLMDB::get_pruned_tx_blobs_from(const crypto::hash& h, size_t coun
return true;
}
bool BlockchainLMDB::get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd) const
bool BlockchainLMDB::get_prunable_tx_blob(const crypto::hash& h, std::string &bd) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -3555,7 +3556,7 @@ bool BlockchainLMDB::for_blocks_range(const uint64_t& h1, const uint64_t& h2, st
if (ret)
throw0(DB_ERROR("Failed to enumerate blocks"));
uint64_t height = *(const uint64_t*)k.mv_data;
blobdata bd;
std::string bd;
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
block b;
if (!parse_and_validate_block_from_blob(bd, b))
@ -3609,12 +3610,14 @@ bool BlockchainLMDB::for_all_transactions(std::function<bool(const crypto::hash&
if (ret)
throw0(DB_ERROR(lmdb_error("Failed to enumerate transactions: ", ret).c_str()));
transaction tx;
blobdata bd;
std::string bd;
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
if (pruned)
{
if (!parse_and_validate_tx_base_from_blob(bd, tx))
{
throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
}
}
else
{
@ -3976,8 +3979,8 @@ void BlockchainLMDB::block_rtxn_abort() const
memset(&m_tinfo->m_ti_rflags, 0, sizeof(m_tinfo->m_ti_rflags));
}
uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated,
const std::vector<std::pair<transaction, blobdata>>& txs)
uint64_t BlockchainLMDB::add_block(const std::pair<block, std::string>& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated,
const std::vector<std::pair<transaction, std::string>>& txs)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -4018,8 +4021,8 @@ static bool convert_checkpoint_into_buffer(checkpoint_t const &checkpoint, check
header.block_hash = checkpoint.block_hash;
header.num_signatures = checkpoint.signatures.size();
native_to_little_inplace(header.height);
native_to_little_inplace(header.num_signatures);
oxenc::host_to_little_inplace(header.height);
oxenc::host_to_little_inplace(header.num_signatures);
size_t const bytes_for_signatures = sizeof(*checkpoint.signatures.data()) * checkpoint.signatures.size();
result.len = sizeof(header) + bytes_for_signatures;
@ -4102,8 +4105,8 @@ static checkpoint_t convert_mdb_val_to_checkpoint(MDB_val const value)
auto const *signatures =
reinterpret_cast<service_nodes::quorum_signature *>(static_cast<uint8_t *>(value.mv_data) + sizeof(*header));
auto num_sigs = little_to_native(header->num_signatures);
result.height = little_to_native(header->height);
auto num_sigs = oxenc::little_to_host(header->num_signatures);
result.height = oxenc::little_to_host(header->height);
result.type = (num_sigs > 0) ? checkpoint_type::service_node : checkpoint_type::hardcoded;
result.block_hash = header->block_hash;
result.signatures.insert(result.signatures.end(), signatures, signatures + num_sigs);
@ -4428,7 +4431,7 @@ std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> BlockchainLMDB::get
while (num_elems > 0) {
const tx_out_index toi = get_output_tx_and_index(amount, num_elems - 1);
const uint64_t height = get_tx_block_height(toi.first);
if (height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= blockchain_height)
if (height + DEFAULT_TX_SPENDABLE_AGE <= blockchain_height)
break;
--num_elems;
}
@ -4561,7 +4564,7 @@ void BlockchainLMDB::add_output_blacklist(std::vector<uint64_t> const &blacklist
throw0(DB_ERROR(lmdb_error("Failed to add blacklisted output to db transaction: ", ret).c_str()));
}
void BlockchainLMDB::add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &block, cryptonote::blobdata const *checkpoint)
void BlockchainLMDB::add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const std::string &block, std::string const *checkpoint)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@ -4604,7 +4607,7 @@ void BlockchainLMDB::add_alt_block(const crypto::hash &blkid, const cryptonote::
}
}
bool BlockchainLMDB::get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *block, cryptonote::blobdata *checkpoint) const
bool BlockchainLMDB::get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, std::string *block, std::string *checkpoint) const
{
LOG_PRINT_L3("BlockchainLMDB:: " << __func__);
check_open();
@ -4692,7 +4695,7 @@ bool BlockchainLMDB::is_read_only() const
uint64_t BlockchainLMDB::get_database_size() const
{
return fs::file_size(m_folder / CRYPTONOTE_BLOCKCHAINDATA_FILENAME);
return fs::file_size(m_folder / BLOCKCHAINDATA_FILENAME);
}
void BlockchainLMDB::fixup(cryptonote::network_type nettype)
@ -4735,7 +4738,7 @@ void BlockchainLMDB::fixup(cryptonote::network_type nettype)
add_timestamp_and_difficulty(nettype, curr_chain_height, timestamps, difficulties, curr_timestamp, curr_cumulative_diff);
// NOTE: Calculate next block difficulty
if (is_hard_fork_at_least(nettype, cryptonote::network_version_16_pulse, curr_height)
if (is_hard_fork_at_least(nettype, hf::hf16_pulse, curr_height)
&& block_header_has_pulse_components(get_block_header_from_height(curr_height)))
{
diff = PULSE_FIXED_DIFFICULTY;
@ -5241,7 +5244,7 @@ void BlockchainLMDB::migrate_0_1()
}
MDB_dbi o_txs;
blobdata bd;
std::string bd;
block b;
MDB_val hk;
@ -5448,7 +5451,7 @@ void BlockchainLMDB::migrate_1_2()
else if (result)
throw0(DB_ERROR(lmdb_error("Failed to get a record from txs: ", result).c_str()));
cryptonote::blobdata bd;
std::string bd;
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
transaction tx;
if (!parse_and_validate_tx_from_blob(bd, tx))
@ -5648,7 +5651,7 @@ void BlockchainLMDB::migrate_3_4()
MDB_val key, val;
uint64_t tx_count = 0;
blobdata bd;
std::string bd;
for(MDB_cursor_op op = MDB_FIRST;; op = MDB_NEXT, bd.clear())
{
transaction tx;
@ -5730,7 +5733,7 @@ void BlockchainLMDB::migrate_3_4()
throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
const uint64_t blockchain_height = db_stats.ms_entries;
boost::circular_buffer<uint64_t> long_term_block_weights(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE);
boost::circular_buffer<uint64_t> long_term_block_weights(LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE);
/* the block_info table name is the same but the old version and new version
* have incompatible data. Create a new table. We want the name to be similar
@ -5796,16 +5799,17 @@ void BlockchainLMDB::migrate_3_4()
throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str()));
if (vb.mv_size == 0)
throw0(DB_ERROR("Invalid data from m_blocks"));
const uint8_t block_major_version = *((const uint8_t*)vb.mv_data);
if (block_major_version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT)
const hf block_major_version{*((const uint8_t*)vb.mv_data)};
if (block_major_version >= feature::LONG_TERM_BLOCK_WEIGHT)
past_long_term_weight = true;
}
uint64_t long_term_block_weight;
if (past_long_term_weight)
{
std::vector<uint64_t> weights(long_term_block_weights.begin(), long_term_block_weights.end());
uint64_t long_term_effective_block_median_weight = std::max<uint64_t>(CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5, epee::misc_utils::median(weights));
uint64_t long_term_effective_block_median_weight = std::max<uint64_t>(
BLOCK_GRANTED_FULL_REWARD_ZONE_V5,
tools::median(std::vector<uint64_t>{long_term_block_weights.begin(), long_term_block_weights.end()}));
long_term_block_weight = std::min<uint64_t>(bi.bi_weight, long_term_effective_block_median_weight + long_term_effective_block_median_weight * 2 / 5);
}
else
@ -5872,7 +5876,7 @@ void BlockchainLMDB::migrate_4_5(cryptonote::network_type nettype)
{
crypto::hash key;
alt_block_data_t data;
cryptonote::blobdata blob;
std::string blob;
};
std::vector<entry_t> new_entries;
@ -5975,12 +5979,12 @@ void BlockchainLMDB::migrate_5_6()
// unexpected padding
auto const *header = static_cast<blk_checkpoint_header const *>(val.mv_data);
auto num_sigs = little_to_native(header->num_signatures);
auto num_sigs = oxenc::little_to_host(header->num_signatures);
auto const *aligned_signatures = reinterpret_cast<service_nodes::quorum_signature *>(static_cast<uint8_t *>(val.mv_data) + sizeof(*header));
if (num_sigs == 0) continue; // NOTE: Hardcoded checkpoints
checkpoint_t checkpoint = {};
checkpoint.height = little_to_native(header->height);
checkpoint.height = oxenc::little_to_host(header->height);
checkpoint.type = (num_sigs > 0) ? checkpoint_type::service_node : checkpoint_type::hardcoded;
checkpoint.block_hash = header->block_hash;
@ -6196,15 +6200,15 @@ void BlockchainLMDB::clear_service_node_data()
}
template <typename C>
C native_to_little_container(const C& c) {
C host_to_little_container(const C& c) {
C result{c};
for (auto& x : result) native_to_little_inplace(x);
for (auto& x : result) oxenc::host_to_little_inplace(x);
return result;
}
template <typename C>
C little_to_native_container(const C& c) {
C little_to_host_container(const C& c) {
C result{c};
for (auto& x : result) little_to_native_inplace(x);
for (auto& x : result) oxenc::little_to_host_inplace(x);
return result;
}
@ -6212,25 +6216,25 @@ struct service_node_proof_serialized_old
{
service_node_proof_serialized_old() = default;
service_node_proof_serialized_old(const service_nodes::proof_info &info)
: timestamp{native_to_little(info.timestamp)},
ip{native_to_little(info.proof->public_ip)},
storage_https_port{native_to_little(info.proof->storage_https_port)},
storage_omq_port{native_to_little(info.proof->storage_omq_port)},
quorumnet_port{native_to_little(info.proof->qnet_port)},
version{native_to_little_container(info.proof->version)},
: timestamp{oxenc::host_to_little(info.timestamp)},
ip{oxenc::host_to_little(info.proof->public_ip)},
storage_https_port{oxenc::host_to_little(info.proof->storage_https_port)},
storage_omq_port{oxenc::host_to_little(info.proof->storage_omq_port)},
quorumnet_port{oxenc::host_to_little(info.proof->qnet_port)},
version{host_to_little_container(info.proof->version)},
pubkey_ed25519{info.proof->pubkey_ed25519}
{}
void update(service_nodes::proof_info &info) const
{
info.timestamp = little_to_native(timestamp);
info.timestamp = oxenc::little_to_host(timestamp);
if (info.timestamp > info.effective_timestamp)
info.effective_timestamp = info.timestamp;
info.proof->public_ip = little_to_native(ip);
info.proof->storage_https_port = little_to_native(storage_https_port);
info.proof->storage_omq_port = little_to_native(storage_omq_port);
info.proof->qnet_port = little_to_native(quorumnet_port);
info.proof->version = little_to_native_container(version);
info.proof->public_ip = oxenc::little_to_host(ip);
info.proof->storage_https_port = oxenc::little_to_host(storage_https_port);
info.proof->storage_omq_port = oxenc::little_to_host(storage_omq_port);
info.proof->qnet_port = oxenc::little_to_host(quorumnet_port);
info.proof->version = little_to_host_container(version);
info.proof->storage_server_version = {0, 0, 0};
info.proof->lokinet_version = {0, 0, 0};
info.update_pubkey(pubkey_ed25519);
@ -6257,8 +6261,8 @@ struct service_node_proof_serialized : service_node_proof_serialized_old {
service_node_proof_serialized() = default;
service_node_proof_serialized(const service_nodes::proof_info &info)
: service_node_proof_serialized_old{info},
storage_server_version{native_to_little_container(info.proof->storage_server_version)},
lokinet_version{native_to_little_container(info.proof->lokinet_version)}
storage_server_version{host_to_little_container(info.proof->storage_server_version)},
lokinet_version{host_to_little_container(info.proof->lokinet_version)}
{}
std::array<uint16_t, 3> storage_server_version{};
std::array<uint16_t, 3> lokinet_version{};
@ -6267,8 +6271,8 @@ struct service_node_proof_serialized : service_node_proof_serialized_old {
void update(service_nodes::proof_info& info) const {
if (!info.proof) info.proof = std::unique_ptr<uptime_proof::Proof>(new uptime_proof::Proof());
service_node_proof_serialized_old::update(info);
info.proof->storage_server_version = little_to_native_container(storage_server_version);
info.proof->lokinet_version = little_to_native_container(lokinet_version);
info.proof->storage_server_version = little_to_host_container(storage_server_version);
info.proof->lokinet_version = little_to_host_container(lokinet_version);
}
operator service_nodes::proof_info() const

View File

@ -29,7 +29,6 @@
#include <atomic>
#include "blockchain_db/blockchain_db.h"
#include "cryptonote_basic/blobdatatype.h" // for type blobdata
#include "ringct/rctTypes.h"
#include "common/fs.h"
#include <boost/thread/thread.hpp>
@ -208,9 +207,9 @@ public:
block_header get_block_header_from_height(uint64_t height) const override;
cryptonote::blobdata get_block_blob(const crypto::hash& h) const override;
std::string get_block_blob(const crypto::hash& h) const override;
cryptonote::blobdata get_block_blob_from_height(uint64_t height) const override;
std::string get_block_blob_from_height(uint64_t height) const override;
std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const override;
@ -249,10 +248,10 @@ public:
uint64_t get_tx_unlock_time(const crypto::hash& h) const override;
bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override;
bool get_pruned_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override;
bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<cryptonote::blobdata> &bd) const override;
bool get_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override;
bool get_tx_blob(const crypto::hash& h, std::string &tx) const override;
bool get_pruned_tx_blob(const crypto::hash& h, std::string &tx) const override;
bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<std::string> &bd) const override;
bool get_prunable_tx_blob(const crypto::hash& h, std::string &tx) const override;
bool get_prunable_tx_hash(const crypto::hash& tx_hash, crypto::hash &prunable_hash) const override;
uint64_t get_tx_count() const override;
@ -277,40 +276,40 @@ public:
bool has_key_image(const crypto::key_image& img) const override;
void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const txpool_tx_meta_t& meta) override;
void add_txpool_tx(const crypto::hash &txid, const std::string &blob, const txpool_tx_meta_t& meta) override;
void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& meta) override;
uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const override;
bool txpool_has_tx(const crypto::hash &txid) const override;
void remove_txpool_tx(const crypto::hash& txid) override;
bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const override;
bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const override;
cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const override;
bool get_txpool_tx_blob(const crypto::hash& txid, std::string &bd) const override;
std::string get_txpool_tx_blob(const crypto::hash& txid) const override;
uint32_t get_blockchain_pruning_seed() const override;
bool prune_blockchain(uint32_t pruning_seed = 0) override;
bool update_pruning() override;
bool check_pruning() override;
void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob, const cryptonote::blobdata *checkpoint) override;
bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob, cryptonote::blobdata *checkpoint) const override;
void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const std::string &blob, const std::string *checkpoint) override;
bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, std::string *blob, std::string *checkpoint) const override;
void remove_alt_block(const crypto::hash &blkid) override;
uint64_t get_alt_block_count() override;
void drop_alt_blocks() override;
bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const override;
bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const std::string*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const override;
bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const override;
bool for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function<bool(uint64_t, const crypto::hash&, const cryptonote::block&)>) const override;
bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const override;
bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const override;
bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const override;
bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *block_blob, const cryptonote::blobdata *checkpoint_blob)> f, bool include_blob = false) const override;
bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const std::string *block_blob, const std::string *checkpoint_blob)> f, bool include_blob = false) const override;
uint64_t add_block( const std::pair<block, blobdata>& blk
uint64_t add_block( const std::pair<block, std::string>& blk
, size_t block_weight
, uint64_t long_term_block_weight
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, const std::vector<std::pair<transaction, blobdata>>& txs
, const std::vector<std::pair<transaction, std::string>>& txs
) override;
void update_block_checkpoint(checkpoint_t const &checkpoint) override;
void remove_block_checkpoint(uint64_t height) override;
@ -376,7 +375,7 @@ private:
void remove_block() override;
uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) override;
uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, std::string>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) override;
void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) override;
@ -446,7 +445,7 @@ private:
template <typename T,
std::enable_if_t<std::is_same_v<T, cryptonote::block> ||
std::is_same_v<T, cryptonote::block_header> ||
std::is_same_v<T, cryptonote::blobdata>, int> = 0>
std::is_same_v<T, std::string>, int> = 0>
T get_and_convert_block_blob_from_height(uint64_t height) const;
MDB_env* m_env;

View File

@ -0,0 +1,571 @@
// Copyright (c) 2021, The Oxen 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 "db_sqlite.h"
#include <sqlite3.h>
#include <sodium.h>
#include <fmt/core.h>
#include <iostream>
#include <cassert>
#include "cryptonote_config.h"
#include "cryptonote_core/blockchain.h"
#include "cryptonote_core/service_node_list.h"
#include "common/string_util.h"
#include "cryptonote_basic/hardfork.h"
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "blockchain.db.sqlite"
namespace cryptonote {
BlockchainSQLite::BlockchainSQLite(cryptonote::network_type nettype, fs::path db_path): db::Database(db_path, ""), m_nettype(nettype), filename {db_path.u8string()} {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
height = 0;
if (!db.tableExists("batched_payments_accrued") || !db.tableExists("batched_payments_raw") || !db.tableExists("batch_db_info")) {
create_schema();
}
height = prepared_get<int64_t>("SELECT height FROM batch_db_info");
}
void BlockchainSQLite::create_schema() {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
db.exec(R"(
CREATE TABLE batched_payments_accrued(
address VARCHAR NOT NULL,
amount BIGINT NOT NULL,
PRIMARY KEY(address),
CHECK(amount >= 0)
);
CREATE TRIGGER batch_payments_delete_empty AFTER UPDATE ON batched_payments_accrued
FOR EACH ROW WHEN NEW.amount = 0 BEGIN
DELETE FROM batched_payments_accrued WHERE address = NEW.address;
END;
CREATE TABLE batched_payments_raw(
address VARCHAR NOT NULL,
amount BIGINT NOT NULL,
height_paid BIGINT NOT NULL,
PRIMARY KEY(address, height_paid),
CHECK(amount >= 0)
);
CREATE INDEX batched_payments_raw_height_idx ON batched_payments_raw(height_paid);
CREATE TABLE batch_db_info(
height BIGINT NOT NULL
);
INSERT INTO batch_db_info(height) VALUES(0);
CREATE TRIGGER batch_payments_prune AFTER UPDATE ON batch_db_info
FOR EACH ROW BEGIN
DELETE FROM batched_payments_raw WHERE height_paid < (NEW.height - 10000);
END;
CREATE VIEW batched_payments_paid AS SELECT * FROM batched_payments_raw;
CREATE TRIGGER make_payment INSTEAD OF INSERT ON batched_payments_paid
FOR EACH ROW BEGIN
UPDATE batched_payments_accrued SET amount = (amount - NEW.amount) WHERE address = NEW.address;
SELECT RAISE(ABORT, 'Address not found') WHERE changes() = 0;
INSERT INTO batched_payments_raw(address, amount, height_paid) VALUES(NEW.address, NEW.amount, NEW.height_paid);
END;
CREATE TRIGGER rollback_payment INSTEAD OF DELETE ON batched_payments_paid
FOR EACH ROW BEGIN
DELETE FROM batched_payments_raw WHERE address = OLD.address AND height_paid = OLD.height_paid;
INSERT INTO batched_payments_accrued(address, amount) VALUES(OLD.address, OLD.amount)
ON CONFLICT(address) DO UPDATE SET amount = (amount + excluded.amount);
END;
)");
MDEBUG("Database setup complete");
}
void BlockchainSQLite::reset_database() {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
db.exec(R"(
DROP TABLE IF EXISTS batched_payments_accrued;
DROP VIEW IF EXISTS batched_payments_paid;
DROP TABLE IF EXISTS batched_payments_raw;
DROP TABLE IF EXISTS batch_db_info;
)");
create_schema();
MDEBUG("Database reset complete");
}
void BlockchainSQLite::update_height(uint64_t new_height) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__ << " Called with new height: " << new_height);
height = new_height;
prepared_exec(
"UPDATE batch_db_info SET height = ?",
static_cast<int64_t>(height));
}
void BlockchainSQLite::increment_height() {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__ << " Called with height: " << height + 1);
update_height(height + 1);
}
void BlockchainSQLite::decrement_height() {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__ << " Called with height: " << height - 1);
update_height(height - 1);
}
bool BlockchainSQLite::add_sn_rewards(const std::vector<cryptonote::batch_sn_payment>& payments) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
auto insert_payment = prepared_st(
"INSERT INTO batched_payments_accrued (address, amount) VALUES (?, ?)"
" ON CONFLICT (address) DO UPDATE SET amount = amount + excluded.amount");
for (auto& payment: payments) {
std::string address_str = cryptonote::get_account_address_as_str(m_nettype, 0, payment.address_info.address);
auto amt = static_cast<int64_t>(payment.amount);
MTRACE(fmt::format("Adding record for SN reward contributor {} to database with amount {}",
address_str, amt));
db::exec_query(insert_payment, address_str, amt);
insert_payment->reset();
}
return true;
}
bool BlockchainSQLite::subtract_sn_rewards(const std::vector<cryptonote::batch_sn_payment>& payments) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
auto update_payment = prepared_st(
"UPDATE batched_payments_accrued SET amount = (amount - ?) WHERE address = ?");
for (auto& payment: payments) {
std::string address_str = cryptonote::get_account_address_as_str(m_nettype, 0, payment.address_info.address);
auto result = db::exec_query(update_payment, static_cast<int64_t>(payment.amount), address_str);
if (!result) {
MERROR("tried to subtract payment from an address that doesn't exist: " << address_str);
return false;
}
update_payment->reset();
}
return true;
}
std::vector<cryptonote::batch_sn_payment> BlockchainSQLite::get_sn_payments(uint64_t block_height) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
// <= here because we might have crap in the db that we don't clear until we actually add the HF
// block later on. (This is a pretty slim edge case that happened on devnet and is probably
// virtually impossible on mainnet).
if (m_nettype != cryptonote::network_type::FAKECHAIN && block_height <= cryptonote::get_hard_fork_heights(m_nettype, hf::hf19_reward_batching).first.value_or(0))
return {};
const auto& conf = get_config(m_nettype);
auto accrued_amounts = prepared_results<std::string, int64_t>(
"SELECT address, amount FROM batched_payments_accrued WHERE amount >= ? ORDER BY address ASC",
static_cast<int64_t>(conf.MIN_BATCH_PAYMENT_AMOUNT * BATCH_REWARD_FACTOR));
std::vector<cryptonote::batch_sn_payment> payments;
for (auto [address, amount] : accrued_amounts) {
if (cryptonote::is_valid_address(address, m_nettype)) {
cryptonote::address_parse_info addr_info {};
cryptonote::get_account_address_from_str(addr_info, m_nettype, address);
uint64_t next_payout_height = addr_info.address.next_payout_height(block_height - 1, conf.BATCHING_INTERVAL);
if (block_height == next_payout_height) {
payments.emplace_back(
std::move(address),
amount / BATCH_REWARD_FACTOR * BATCH_REWARD_FACTOR /* truncate to atomic OXEN */,
m_nettype);
}
} else {
MERROR("Invalid address returned from batching database: " << address);
}
}
return payments;
}
uint64_t BlockchainSQLite::get_accrued_earnings(const std::string& address) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
SQLite::Statement select_earnings {
db,
"SELECT amount FROM batched_payments_accrued WHERE address = ?;"
};
select_earnings.bind(1, address);
uint64_t amount{};
while (select_earnings.executeStep()) {
amount = static_cast<uint64_t>(select_earnings.getColumn(0).getInt64() / 1000);
}
return amount;
}
std::pair<std::vector<std::string>, std::vector<uint64_t>> BlockchainSQLite::get_all_accrued_earnings() {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
SQLite::Statement select_earnings {
db,
"SELECT address, amount FROM batched_payments_accrued;"
};
std::vector<uint64_t> amounts;
std::vector<std::string> addresses;
while (select_earnings.executeStep()) {
addresses.emplace_back(select_earnings.getColumn(0).getString());
amounts.emplace_back(static_cast<uint64_t>(select_earnings.getColumn(1).getInt64() / 1000));
}
return std::make_pair(addresses, amounts);
}
std::vector<cryptonote::batch_sn_payment> BlockchainSQLite::calculate_rewards(hf hf_version, uint64_t distribution_amount, service_nodes::service_node_info sn_info) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
// Find out how much is due for the operator: fee_portions/PORTIONS * reward
assert(sn_info.portions_for_operator <= old::STAKING_PORTIONS);
uint64_t operator_fee = mul128_div64(sn_info.portions_for_operator, distribution_amount, old::STAKING_PORTIONS);
assert(operator_fee <= distribution_amount);
std::vector<cryptonote::batch_sn_payment> payments;
// Pay the operator fee to the operator
if (operator_fee > 0)
payments.emplace_back(sn_info.operator_address, operator_fee, m_nettype);
// Pay the balance to all the contributors (including the operator again)
uint64_t total_contributed_to_sn = std::accumulate(
sn_info.contributors.begin(),
sn_info.contributors.end(),
uint64_t(0),
[](auto&& a, auto&& b) { return a + b.amount; });
for (auto& contributor: sn_info.contributors) {
// This calculates (contributor.amount / total_contributed_to_winner_sn) * (distribution_amount - operator_fee) but using 128 bit integer math
uint64_t c_reward = mul128_div64(contributor.amount, distribution_amount - operator_fee, total_contributed_to_sn);
if (c_reward > 0)
payments.emplace_back(contributor.address, c_reward, m_nettype);
}
return payments;
}
// Calculates block rewards, then invokes either `add_sn_rewards` (if `add`) or
// `subtract_sn_rewards` (if `!add`) to process them.
bool BlockchainSQLite::reward_handler(
const cryptonote::block& block,
const service_nodes::service_node_list::state_t& service_nodes_state,
bool add)
{
// The method we call do actually handle the change: either `add_sn_payments` if add is true,
// `subtract_sn_payments` otherwise:
bool (BlockchainSQLite::* add_or_subtract)(const std::vector<cryptonote::batch_sn_payment>&)
= add ? &BlockchainSQLite::add_sn_rewards : &BlockchainSQLite::subtract_sn_rewards;
// From here on we calculate everything in milli-atomic OXEN (i.e. thousanths of an atomic
// OXEN) so that our integer math has minimal loss from integer division.
if (block.reward > std::numeric_limits<uint64_t>::max() / BATCH_REWARD_FACTOR)
throw std::logic_error{"Reward distribution amount is too large"};
uint64_t block_reward = block.reward * BATCH_REWARD_FACTOR;
uint64_t service_node_reward = cryptonote::service_node_reward_formula(0, block.major_version) * BATCH_REWARD_FACTOR;
// Step 1: Pay out the block producer their tx fees (note that, unlike the below, this applies
// even if the SN isn't currently payable).
if (block_reward < service_node_reward && m_nettype != cryptonote::network_type::FAKECHAIN)
throw std::logic_error{"Invalid payment: block reward is too small"};
if (uint64_t tx_fees = block_reward - service_node_reward;
tx_fees > 0
&& block.service_node_winner_key // "service_node_winner_key" tracks the pulse winner; 0 if a mined block
&& crypto_core_ed25519_is_valid_point(reinterpret_cast<const unsigned char *>(block.service_node_winner_key.data))
) {
if (auto service_node_winner = service_nodes_state.service_nodes_infos.find(block.service_node_winner_key);
service_node_winner != service_nodes_state.service_nodes_infos.end()) {
auto tx_fee_payments = calculate_rewards(block.major_version, tx_fees, *service_node_winner->second);
// Takes the block producer and adds its contributors to the batching database for the transaction fees
if (!(this->*add_or_subtract)(tx_fee_payments))
return false;
}
}
auto block_height = get_block_height(block);
// Step 2: Iterate over the whole service node list and pay each node 1/service_node_list fraction
const auto payable_service_nodes = service_nodes_state.payable_service_nodes_infos(block_height, m_nettype);
size_t total_service_nodes_payable = payable_service_nodes.size();
for (const auto& [node_pubkey, node_info]: payable_service_nodes) {
auto payable_service_node = service_nodes_state.service_nodes_infos.find(node_pubkey);
if (payable_service_node == service_nodes_state.service_nodes_infos.end())
continue;
auto snode_rewards = calculate_rewards(block.major_version, service_node_reward / total_service_nodes_payable, * payable_service_node -> second);
// Takes the node and adds its contributors to the batching database
if (!(this->*add_or_subtract)(snode_rewards))
return false;
}
// Step 3: Add Governance reward to the list
if (m_nettype != cryptonote::network_type::FAKECHAIN) {
std::vector<cryptonote::batch_sn_payment> governance_rewards;
cryptonote::address_parse_info governance_wallet_address;
cryptonote::get_account_address_from_str(governance_wallet_address, m_nettype,
cryptonote::get_config(m_nettype).governance_wallet_address(block.major_version));
uint64_t foundation_reward = cryptonote::governance_reward_formula(block.major_version) * BATCH_REWARD_FACTOR;
governance_rewards.emplace_back(governance_wallet_address.address, foundation_reward, m_nettype);
if (!(this->*add_or_subtract)(governance_rewards))
return false;
}
return true;
}
bool BlockchainSQLite::add_block(const cryptonote::block& block,
const service_nodes::service_node_list::state_t& service_nodes_state) {
auto block_height = get_block_height(block);
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__ << " called on height: " << block_height);
auto hf_version = block.major_version;
if (hf_version < hf::hf19_reward_batching) {
update_height(block_height);
return true;
}
auto fork_height = cryptonote::get_hard_fork_heights(m_nettype, hf::hf19_reward_batching);
if (block_height == fork_height.first.value_or(0)) {
MDEBUG("Batching of Service Node Rewards Begins");
reset_database();
update_height(block_height - 1);
}
if (block_height != height + 1) {
MERROR(fmt::format("Block height ({}) out of sync with batching database ({})", block_height, height));
return false;
}
// We query our own database as a source of truth to verify the blocks payments against. The calculated_rewards
// variable contains a known good list of who should have been paid in this block
auto calculated_rewards = get_sn_payments(block_height);
// We iterate through the block's coinbase payments and build a copy of our own list of the payments
// miner_tx_vouts this will be compared against calculated_rewards and if they match we know the block is
// paying the correct people only.
std::vector<std::tuple<crypto::public_key, uint64_t>> miner_tx_vouts;
for (auto & vout: block.miner_tx.vout)
miner_tx_vouts.emplace_back(var::get<txout_to_key>(vout.target).key, vout.amount);
try {
SQLite::Transaction transaction {
db,
SQLite::TransactionBehavior::IMMEDIATE
};
// Goes through the miner transactions vouts checks they are right and marks them as paid in the database
if (!validate_batch_payment(miner_tx_vouts, calculated_rewards, block_height)) {
return false;
}
if (!reward_handler(block, service_nodes_state, /*add=*/ true))
return false;
increment_height();
transaction.commit();
} catch (std::exception& e) {
MFATAL("Error adding reward payments: " << e.what());
return false;
}
return true;
}
bool BlockchainSQLite::pop_block(const cryptonote::block& block,
const service_nodes::service_node_list::state_t& service_nodes_state) {
auto block_height = get_block_height(block);
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__ << " called on height: " << block_height);
if (height < block_height) {
MDEBUG("Block above batching DB height skipping pop");
return true;
}
if (block_height != height) {
MERROR("Block height out of sync with batching database");
return false;
}
const auto& conf = get_config(m_nettype);
auto hf_version = block.major_version;
if (hf_version < hf::hf19_reward_batching) {
decrement_height();
return true;
}
try {
SQLite::Transaction transaction {
db,
SQLite::TransactionBehavior::IMMEDIATE
};
if (!reward_handler(block, service_nodes_state, /*add=*/ false))
return false;
// Add back to the database payments that had been made in this block
delete_block_payments(block_height);
decrement_height();
transaction.commit();
} catch (std::exception& e) {
MFATAL("Error subtracting reward payments: " << e.what());
return false;
}
return true;
}
bool BlockchainSQLite::validate_batch_payment(
const std::vector<std::tuple<crypto::public_key, uint64_t>>& miner_tx_vouts,
const std::vector<cryptonote::batch_sn_payment>& calculated_payments_from_batching_db,
uint64_t block_height) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
if (miner_tx_vouts.size() != calculated_payments_from_batching_db.size()) {
MERROR(fmt::format("Length of batch payments ({}) does not match block vouts ({})", calculated_payments_from_batching_db.size(), miner_tx_vouts.size()));
return false;
}
int8_t vout_index = 0;
uint64_t total_oxen_payout_in_our_db = std::accumulate(
calculated_payments_from_batching_db.begin(),
calculated_payments_from_batching_db.end(),
uint64_t(0),
[](auto&& a, auto&& b) { return a + b.amount; });
uint64_t total_oxen_payout_in_vouts = 0;
std::vector<batch_sn_payment> finalised_payments;
cryptonote::keypair
const deterministic_keypair = cryptonote::get_deterministic_keypair_from_height(block_height);
for (size_t vout_index = 0; vout_index < miner_tx_vouts.size(); vout_index++) {
const auto& [pubkey, amt] = miner_tx_vouts[vout_index];
uint64_t amount = amt * BATCH_REWARD_FACTOR;
const auto& from_db = calculated_payments_from_batching_db[vout_index];
if (amount != from_db.amount) {
MERROR(fmt::format("Batched payout amount incorrect. Should be {}, not {}", from_db.amount, amount));
return false;
}
crypto::public_key out_eph_public_key{};
if (!cryptonote::get_deterministic_output_key(from_db.address_info.address, deterministic_keypair, vout_index, out_eph_public_key)) {
MERROR("Failed to generate output one-time public key");
return false;
}
if (tools::view_guts(pubkey) != tools::view_guts(out_eph_public_key)) {
MERROR("Output ephemeral public key does not match");
return false;
}
total_oxen_payout_in_vouts += amount;
finalised_payments.emplace_back(from_db.address, amount, m_nettype);
}
if (total_oxen_payout_in_vouts != total_oxen_payout_in_our_db) {
MERROR(fmt::format("Total batched payout amount incorrect. Should be {}, not {}", total_oxen_payout_in_our_db, total_oxen_payout_in_vouts));
return false;
}
return save_payments(block_height, finalised_payments);
}
bool BlockchainSQLite::save_payments(uint64_t block_height, const std::vector<batch_sn_payment>& paid_amounts) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__);
auto select_sum = prepared_st(
"SELECT amount from batched_payments_accrued WHERE address = ?");
auto update_paid = prepared_st(
"INSERT INTO batched_payments_paid (address, amount, height_paid) VALUES (?,?,?)");
for (const auto& payment: paid_amounts) {
if (auto maybe_amount = db::exec_and_maybe_get<int64_t>(select_sum, payment.address))
{
// Truncate the thousanths amount to an atomic OXEN:
auto amount = static_cast<uint64_t>(*maybe_amount) / BATCH_REWARD_FACTOR * BATCH_REWARD_FACTOR;
if (amount != payment.amount) {
MERROR(fmt::format("Invalid amounts passed in to save payments for address {}: received {}, expected {} (truncated from {})",
payment.address, payment.amount, amount, *maybe_amount));
return false;
}
db::exec_query(update_paid, payment.address, static_cast<int64_t>(amount), static_cast<int64_t>(block_height));
update_paid->reset();
}
else {
// This shouldn't occur: we validate payout addresses much earlier in the block validation.
MERROR(fmt::format("Internal error: Invalid amounts passed in to save payments for address {}: that address has no accrued rewards",
payment.address));
return false;
}
select_sum->reset();
}
return true;
}
std::vector<cryptonote::batch_sn_payment> BlockchainSQLite::get_block_payments(uint64_t block_height) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__ << " Called with height: " << block_height);
std::vector<cryptonote::batch_sn_payment> payments_at_height;
auto paid = prepared_results<std::string, int64_t>(
"SELECT address, amount FROM batched_payments_paid WHERE height_paid = ? ORDER BY address",
static_cast<int64_t>(block_height));
for (auto [addr, amt] : paid)
payments_at_height.emplace_back(std::move(addr), static_cast<uint64_t>(amt), m_nettype);
return payments_at_height;
}
bool BlockchainSQLite::delete_block_payments(uint64_t block_height) {
LOG_PRINT_L3("BlockchainDB_SQLITE::" << __func__ << " Called with height: " << block_height);
prepared_exec(
"DELETE FROM batched_payments_paid WHERE height_paid >= ?",
static_cast<int64_t>(block_height));
return true;
}
} // namespace cryptonote

View File

@ -0,0 +1,122 @@
// Copyright (c) 2021, The Oxen 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.
#pragma once
#include <string>
#include <filesystem>
#include "epee/misc_log_ex.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "sqlitedb/database.hpp"
#include "common/fs.h"
#include <SQLiteCpp/SQLiteCpp.h>
namespace cryptonote
{
fs::path check_if_copy_filename(std::string_view db_path);
class BlockchainSQLite : public db::Database
{
public:
explicit BlockchainSQLite(cryptonote::network_type nettype, fs::path db_path);
BlockchainSQLite(const BlockchainSQLite&) = delete;
// Database management functions. Should be called on creation of BlockchainSQLite
void create_schema();
void reset_database();
// The batching database maintains a height variable to know if it gets out of sync with the mainchain. Calling increment and decrement is the primary method of interacting with this height variable
void update_height(uint64_t new_height);
void increment_height();
void decrement_height();
// add_sn_payments/subtract_sn_payments -> passing an array of addresses and amounts. These will be added or subtracted to the database for each address specified. If the address does not exist it will be created.
bool add_sn_rewards(const std::vector<cryptonote::batch_sn_payment>& payments);
bool subtract_sn_rewards(const std::vector<cryptonote::batch_sn_payment>& payments);
private:
bool reward_handler(
const cryptonote::block& block,
const service_nodes::service_node_list::state_t& service_nodes_state,
bool add);
public:
// get_accrued_earnings -> queries the database for the amount that has been accrued to `service_node_address` will return the atomic value in oxen that
// the service node is owed.
uint64_t get_accrued_earnings(const std::string& address);
// get_all_accrued_earnings -> queries the database for all the amount that has been accrued to service nodes will return
// 2 vectors corresponding to the addresses and the atomic value in oxen that the service nodes are owed.
std::pair<std::vector<std::string>, std::vector<uint64_t>> get_all_accrued_earnings();
// get_payments -> passing a block height will return an array of payments that should be created in a coinbase transaction on that block given the current batching DB state.
std::vector<cryptonote::batch_sn_payment> get_sn_payments(uint64_t block_height);
// calculate_rewards -> takes the list of contributors from sn_info with their SN contribution
// amounts and will calculate how much of the block rewards should be the allocated to the
// contributors. The function will return a list suitable for passing to add_sn_payments
//
// Note that distribution_amount here is typically passed as milli-atomic OXEN for extra
// precision.
std::vector<cryptonote::batch_sn_payment> calculate_rewards(hf hf_version, uint64_t distribution_amount, service_nodes::service_node_info sn_info);
// add/pop_block -> takes a block that contains new block rewards to be batched and added to the database
// and/or batching payments that need to be subtracted from the database, in addition it takes a reference to
// the service node state which it will use to calculate the individual payouts.
// The function will then process this block add and subtracting to the batching DB appropriately.
// This is the primary entry point for the blockchain to add to the batching database.
// Each accepted block should call this passing in the SN list structure.
bool add_block(const cryptonote::block& block, const service_nodes::service_node_list::state_t& service_nodes_state);
bool pop_block(const cryptonote::block& block, const service_nodes::service_node_list::state_t& service_nodes_state);
// validate_batch_payment -> used to make sure that list of miner_tx_vouts is correct. Compares the miner_tx_vouts with a list previously extracted payments to make sure that the correct persons are being paid.
bool validate_batch_payment(
const std::vector<std::tuple<crypto::public_key, uint64_t>>& miner_tx_vouts,
const std::vector<cryptonote::batch_sn_payment>& calculated_payments_from_batching_db,
uint64_t block_height);
// these keep track of payments made to SN operators after then payment has been made. Allows for popping blocks back and knowing who got paid in those blocks.
// passing in a list of people to be marked as paid in the paid_amounts vector. Block height will be added to the batched_payments_paid database as height_paid.
bool save_payments(uint64_t block_height, const std::vector<batch_sn_payment>& paid_amounts);
std::vector<cryptonote::batch_sn_payment> get_block_payments(uint64_t block_height);
bool delete_block_payments(uint64_t block_height);
uint64_t height;
protected:
cryptonote::network_type m_nettype;
std::string filename;
};
}

View File

@ -43,7 +43,7 @@ namespace cryptonote
class BaseTestDB: public cryptonote::BlockchainDB {
public:
BaseTestDB() {}
virtual void open(const fs::path& filename, network_type nettype = FAKECHAIN, const int db_flags = 0) override { }
virtual void open(const fs::path& filename, network_type nettype = network_type::FAKECHAIN, const int db_flags = 0) override { }
virtual void close() override {}
virtual void sync() override {}
virtual void safesyncmode(const bool onoff) override {}
@ -66,13 +66,13 @@ public:
virtual void block_rtxn_abort() const override {}
virtual bool block_exists(const crypto::hash& h, uint64_t *height) const override { return false; }
virtual cryptonote::blobdata get_block_blob_from_height(uint64_t height) const override { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); }
virtual cryptonote::blobdata get_block_blob(const crypto::hash& h) const override { return cryptonote::blobdata(); }
virtual std::string get_block_blob_from_height(uint64_t height) const override { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); }
virtual std::string get_block_blob(const crypto::hash& h) const override { return std::string(); }
virtual cryptonote::block_header get_block_header_from_height(uint64_t height) const override { return get_block_from_height(height); }
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_prunable_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override { return false; }
virtual bool get_tx_blob(const crypto::hash& h, std::string &tx) const override { return false; }
virtual bool get_pruned_tx_blob(const crypto::hash& h, std::string &tx) const override { return false; }
virtual bool get_pruned_tx_blobs_from(const crypto::hash& h, size_t count, std::vector<std::string> &bd) const override { return false; }
virtual bool get_prunable_tx_blob(const crypto::hash& h, std::string &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; }
virtual uint64_t get_block_timestamp(const uint64_t& height) const override { return 0; }
@ -110,7 +110,7 @@ public:
virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_index, size_t n_txes) const override { return std::vector<std::vector<uint64_t>>(); }
virtual bool has_key_image(const crypto::key_image& img) const override { return false; }
virtual void remove_block() override { }
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<cryptonote::transaction, cryptonote::blobdata>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) override {return 0;}
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<cryptonote::transaction, std::string>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) override {return 0;}
virtual void remove_transaction_data(const crypto::hash& tx_hash, const cryptonote::transaction& tx) override {}
virtual uint64_t add_output(const crypto::hash& tx_hash, const cryptonote::tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) override {return 0;}
virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<uint64_t>& amount_output_indices) override {}
@ -126,16 +126,16 @@ public:
virtual std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> get_output_histogram(const std::vector<uint64_t> &amounts, bool unlocked, uint64_t recent_cutoff, uint64_t min_count) const override { return std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>>(); }
virtual bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, std::vector<uint64_t> &distribution, uint64_t &base) const override { return false; }
virtual void add_txpool_tx(const crypto::hash &txid, const cryptonote::blobdata &blob, const cryptonote::txpool_tx_meta_t& details) override {}
virtual void add_txpool_tx(const crypto::hash &txid, const std::string &blob, const cryptonote::txpool_tx_meta_t& details) override {}
virtual void update_txpool_tx(const crypto::hash &txid, const cryptonote::txpool_tx_meta_t& details) override {}
virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const override { return 0; }
virtual bool txpool_has_tx(const crypto::hash &txid) const override { return false; }
virtual void remove_txpool_tx(const crypto::hash& txid) override {}
virtual bool get_txpool_tx_meta(const crypto::hash& txid, cryptonote::txpool_tx_meta_t &meta) const override { return false; }
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const override { return false; }
virtual bool get_txpool_tx_blob(const crypto::hash& txid, std::string &bd) const override { return false; }
virtual uint64_t get_database_size() const override { return 0; }
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const override { return ""; }
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = false) const override { return false; }
virtual std::string get_txpool_tx_blob(const crypto::hash& txid) const override { return ""; }
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const std::string*)>, bool include_blob = false, bool include_unrelayed_txes = false) const override { return false; }
virtual void add_block( const cryptonote::block& blk
, size_t block_weight
@ -173,12 +173,12 @@ public:
void set_service_node_proof(const crypto::public_key &pubkey, const service_nodes::proof_info &proof) override { }
bool remove_service_node_proof(const crypto::public_key &pubkey) override { return false; }
virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob, const cryptonote::blobdata *checkpoint) override {}
virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob, cryptonote::blobdata *checkpoint) const override { return false; }
virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const std::string &blob, const std::string *checkpoint) override {}
virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, std::string *blob, std::string *checkpoint) const override { return false; }
virtual void remove_alt_block(const crypto::hash &blkid) override {}
virtual uint64_t get_alt_block_count() override { return 0; }
virtual void drop_alt_blocks() override {}
virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *block_blob, const cryptonote::blobdata *checkpoint_blob)> f, bool include_blob = false) const override { return true; }
virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const std::string *block_blob, const std::string *checkpoint_blob)> f, bool include_blob = false) const override { return true; }
};
}

View File

@ -34,6 +34,7 @@ target_link_libraries(blockchain_tools_common_libs INTERFACE
version
filesystem
Boost::program_options
SQLiteCpp
extra)

View File

@ -231,7 +231,7 @@ static bool get_block_from_height(ancestry_state_t &state, BlockchainDB *db, uin
b = state.block_cache[height];
return true;
}
cryptonote::blobdata bd = db->get_block_blob_from_height(height);
std::string bd = db->get_block_blob_from_height(height);
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
{
LOG_PRINT_L0("Bad block from db");
@ -256,7 +256,7 @@ static bool get_transaction(ancestry_state_t &state, BlockchainDB *db, const cry
return true;
}
cryptonote::blobdata bd;
std::string bd;
if (!db->get_pruned_tx_blob(txid, bd))
{
LOG_PRINT_L0("Failed to get txid " << txid << " from db");
@ -400,7 +400,7 @@ int main(int argc, char* argv[])
std::string opt_data_dir = command_line::get_arg(vm, cryptonote::arg_data_dir);
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
bool opt_devnet = command_line::get_arg(vm, cryptonote::arg_devnet_on);
network_type net_type = opt_testnet ? TESTNET : opt_devnet ? DEVNET : MAINNET;
network_type net_type = opt_testnet ? network_type::TESTNET : opt_devnet ? network_type::DEVNET : network_type::MAINNET;
std::string opt_txid_string = command_line::get_arg(vm, arg_txid);
std::string opt_output_string = command_line::get_arg(vm, arg_output);
uint64_t opt_height = command_line::get_arg(vm, arg_height);
@ -458,7 +458,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, nullptr /*ons_db*/, net_type);
r = core_storage->init(db, nullptr /*ons_db*/, nullptr, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");
@ -499,7 +499,7 @@ int main(int argc, char* argv[])
for (uint64_t h = state.height; h < db_height; ++h)
{
size_t block_ancestry_size = 0;
const cryptonote::blobdata bd = db->get_block_blob_from_height(h);
const std::string bd = db->get_block_blob_from_height(h);
++total_blocks;
cryptonote::block b;
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
@ -532,7 +532,7 @@ int main(int argc, char* argv[])
}
else
{
cryptonote::blobdata bd;
std::string bd;
if (!db->get_pruned_tx_blob(txid, bd))
{
LOG_PRINT_L0("Failed to get txid " << txid << " from db");
@ -629,7 +629,7 @@ int main(int argc, char* argv[])
}
else
{
const cryptonote::blobdata bd = db->get_block_blob_from_height(opt_height);
const std::string bd = db->get_block_blob_from_height(opt_height);
cryptonote::block b;
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
{

View File

@ -471,7 +471,7 @@ static bool for_all_transactions(const fs::path& filename, const uint64_t& start
if (k.mv_size != sizeof(uint64_t))
throw std::runtime_error("Bad key size");
uint64_t height = *(const uint64_t*)k.mv_data;
blobdata bd;
std::string bd;
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
block b;
if (!parse_and_validate_block_from_blob(bd, b))

View File

@ -28,6 +28,7 @@
#include "common/command_line.h"
#include "common/varint.h"
#include "common/median.h"
#include "cryptonote_core/cryptonote_core.h"
#include "blockchain_objects.h"
#include "blockchain_db/blockchain_db.h"
@ -99,7 +100,7 @@ int main(int argc, char* argv[])
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
bool opt_devnet = command_line::get_arg(vm, cryptonote::arg_devnet_on);
network_type net_type = opt_testnet ? TESTNET : opt_devnet ? DEVNET : MAINNET;
network_type net_type = opt_testnet ? network_type::TESTNET : opt_devnet ? network_type::DEVNET : network_type::MAINNET;
std::string opt_txid_string = command_line::get_arg(vm, arg_txid);
uint64_t opt_height = command_line::get_arg(vm, arg_height);
bool opt_include_coinbase = command_line::get_arg(vm, arg_include_coinbase);
@ -142,7 +143,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, nullptr /*ons_db*/, net_type);
r = core_storage->init(db, nullptr /*ons_db*/, nullptr, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");
@ -154,7 +155,7 @@ int main(int argc, char* argv[])
}
else
{
const cryptonote::blobdata bd = db->get_block_blob_from_height(opt_height);
const std::string bd = db->get_block_blob_from_height(opt_height);
cryptonote::block b;
if (!cryptonote::parse_and_validate_block_from_blob(bd, b))
{
@ -187,7 +188,7 @@ int main(int argc, char* argv[])
std::vector<crypto::hash> new_txids;
for (const crypto::hash &txid: txids)
{
cryptonote::blobdata bd;
std::string bd;
if (!db->get_pruned_tx_blob(txid, bd))
{
LOG_PRINT_L0("Failed to get txid " << txid << " from db");
@ -305,7 +306,7 @@ done:
for (uint64_t depth: depths)
cumulative_depth += depth;
LOG_PRINT_L0("Average min depth for " << start_txids.size() << " transaction(s): " << cumulative_depth/(float)depths.size());
LOG_PRINT_L0("Median min depth for " << start_txids.size() << " transaction(s): " << epee::misc_utils::median(depths));
LOG_PRINT_L0("Median min depth for " << start_txids.size() << " transaction(s): " << tools::median(std::move(depths)));
core_storage->deinit();
return 0;

View File

@ -142,7 +142,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, nullptr, opt_testnet ? cryptonote::TESTNET : opt_devnet ? cryptonote::DEVNET : cryptonote::MAINNET);
r = core_storage->init(db, nullptr, nullptr, opt_testnet ? cryptonote::network_type::TESTNET : opt_devnet ? cryptonote::network_type::DEVNET : cryptonote::network_type::MAINNET);
if (core_storage->get_blockchain_pruning_seed() && !opt_blocks_dat)
{

View File

@ -404,12 +404,12 @@ int import_from_file(cryptonote::core& core, const fs::path& import_file_path, u
if (opt_verify)
{
cryptonote::blobdata block;
std::string block;
cryptonote::block_to_blob(bp.block, block);
std::vector<cryptonote::blobdata> txs;
std::vector<std::string> txs;
for (const auto &tx: bp.txs)
{
txs.push_back(cryptonote::blobdata());
txs.push_back(std::string());
cryptonote::tx_to_blob(tx, txs.back());
}
blocks.push_back({block, txs});
@ -422,7 +422,7 @@ int import_from_file(cryptonote::core& core, const fs::path& import_file_path, u
}
else
{
std::vector<std::pair<transaction, blobdata>> txs;
std::vector<std::pair<transaction, std::string>> txs;
std::vector<transaction> archived_txs;
archived_txs = bp.txs;

View File

@ -304,7 +304,7 @@ static void prune(MDB_env *env0, MDB_env *env1)
if (dbr) throw std::runtime_error("Failed to open LMDB dbi: " + std::string(mdb_strerror(dbr)));
MDB_val k, v;
uint32_t pruning_seed = tools::make_pruning_seed(tools::get_random_stripe(), CRYPTONOTE_PRUNING_LOG_STRIPES);
uint32_t pruning_seed = tools::make_pruning_seed(tools::get_random_stripe(), PRUNING_LOG_STRIPES);
static char pruning_seed_key[] = "pruning_seed";
k.mv_data = pruning_seed_key;
k.mv_size = strlen("pruning_seed") + 1;
@ -334,7 +334,7 @@ static void prune(MDB_env *env0, MDB_env *env1)
const txindex *ti = (const txindex*)v.mv_data;
const uint64_t block_height = ti->data.block_id;
MDB_val_set(kk, ti->data.tx_id);
if (block_height + CRYPTONOTE_PRUNING_TIP_BLOCKS >= blockchain_height)
if (block_height + PRUNING_TIP_BLOCKS >= blockchain_height)
{
MDEBUG(block_height << "/" << blockchain_height << " is in tip");
MDB_val_set(vv, block_height);
@ -494,7 +494,7 @@ int main(int argc, char* argv[])
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
bool opt_devnet = command_line::get_arg(vm, cryptonote::arg_devnet_on);
network_type net_type = opt_testnet ? TESTNET : opt_devnet ? DEVNET : MAINNET;
network_type net_type = opt_testnet ? network_type::TESTNET : opt_devnet ? network_type::DEVNET : network_type::MAINNET;
bool opt_copy_pruned_database = command_line::get_arg(vm, arg_copy_pruned_database);
std::string data_dir = command_line::get_arg(vm, cryptonote::arg_data_dir);
while (tools::ends_with(data_dir, "/") || tools::ends_with(data_dir, "\\"))

View File

@ -160,7 +160,7 @@ int main(int argc, char* argv[])
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
bool opt_devnet = command_line::get_arg(vm, cryptonote::arg_devnet_on);
network_type net_type = opt_testnet ? TESTNET : opt_devnet ? DEVNET : MAINNET;
network_type net_type = opt_testnet ? network_type::TESTNET : opt_devnet ? network_type::DEVNET : network_type::MAINNET;
bool opt_verbose = command_line::get_arg(vm, arg_verbose);
bool opt_dry_run = command_line::get_arg(vm, arg_dry_run);

View File

@ -115,7 +115,7 @@ int main(int argc, char* argv[])
std::string opt_data_dir = command_line::get_arg(vm, cryptonote::arg_data_dir);
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
bool opt_devnet = command_line::get_arg(vm, cryptonote::arg_devnet_on);
network_type net_type = opt_testnet ? TESTNET : opt_devnet ? DEVNET : MAINNET;
network_type net_type = opt_testnet ? network_type::TESTNET : opt_devnet ? network_type::DEVNET : network_type::MAINNET;
block_start = command_line::get_arg(vm, arg_block_start);
block_stop = command_line::get_arg(vm, arg_block_stop);
bool do_inputs = command_line::get_arg(vm, arg_inputs);
@ -145,7 +145,7 @@ int main(int argc, char* argv[])
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->init(db, nullptr /*ons_db*/, net_type);
r = core_storage->init(db, nullptr /*ons_db*/, nullptr, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");
@ -208,7 +208,7 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
for (uint64_t h = block_start; h < block_stop; ++h)
{
cryptonote::blobdata bd = db->get_block_blob_from_height(h);
std::string bd = db->get_block_blob_from_height(h);
cryptonote::block blk;
if (!cryptonote::parse_and_validate_block_from_blob(bd, blk))
{

View File

@ -132,7 +132,7 @@ int main(int argc, char* argv[])
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
bool opt_devnet = command_line::get_arg(vm, cryptonote::arg_devnet_on);
network_type net_type = opt_testnet ? TESTNET : opt_devnet ? DEVNET : MAINNET;
network_type net_type = opt_testnet ? network_type::TESTNET : opt_devnet ? network_type::DEVNET : network_type::MAINNET;
bool opt_rct_only = command_line::get_arg(vm, arg_rct_only);
// If we wanted to use the memory pool, we would set up a fake_core.
@ -172,7 +172,7 @@ int main(int argc, char* argv[])
return 1;
}
r = core_storage->init(db, nullptr /*ons_db*/, net_type);
r = core_storage->init(db, nullptr /*ons_db*/, nullptr, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");

View File

@ -138,7 +138,7 @@ bool BootstrapFile::initialize_file()
uint32_t bd_size = 0;
blobdata bd = t_serializable_object_to_blob(bfi);
std::string bd = t_serializable_object_to_blob(bfi);
MDEBUG("bootstrap::file_info size: " << bd.size());
bd_size = bd.size();
@ -248,7 +248,7 @@ void BootstrapFile::write_block(block& block)
bp.coins_generated = coins_generated;
}
blobdata bd = t_serializable_object_to_blob(bp);
std::string bd = t_serializable_object_to_blob(bp);
m_output_stream->write((const char*)bd.data(), bd.size());
}

View File

@ -4,8 +4,8 @@ extern "C" {
}
#include <iostream>
#include <fstream>
#include <oxenmq/hex.h>
#include <oxenmq/base32z.h>
#include <oxenc/hex.h>
#include <oxenc/base32z.h>
#include <string_view>
#include <string>
#include <list>
@ -137,7 +137,7 @@ int generate(bool ed25519, std::list<std::string_view> args) {
return error(11, "Internal error: pubkey check failed");
if (pubkey_pos != std::string::npos)
filename.replace(pubkey_pos, 6, oxenmq::to_hex(pubkey.begin(), pubkey.end()));
filename.replace(pubkey_pos, 6, oxenc::to_hex(pubkey.begin(), pubkey.end()));
fs::ofstream out{fs::u8path(filename), std::ios::trunc | std::ios::binary};
if (!out.good())
return error(2, "Failed to open output file '" + filename + "': " + std::strerror(errno));
@ -156,11 +156,11 @@ int generate(bool ed25519, std::list<std::string_view> args) {
if (0 != crypto_sign_ed25519_pk_to_curve25519(x_pubkey.data(), pubkey.data()))
return error(14, "Internal error: unable to convert Ed25519 pubkey to X25519 pubkey");
std::cout <<
"Public key: " << oxenmq::to_hex(pubkey.begin(), pubkey.end()) <<
"\nX25519 pubkey: " << oxenmq::to_hex(x_pubkey.begin(), x_pubkey.end()) <<
"\nLokinet address: " << oxenmq::to_base32z(pubkey.begin(), pubkey.end()) << ".snode\n";
"Public key: " << oxenc::to_hex(pubkey.begin(), pubkey.end()) <<
"\nX25519 pubkey: " << oxenc::to_hex(x_pubkey.begin(), x_pubkey.end()) <<
"\nLokinet address: " << oxenc::to_base32z(pubkey.begin(), pubkey.end()) << ".snode\n";
} else {
std::cout << "Public key: " << oxenmq::to_hex(pubkey.begin(), pubkey.end()) << "\n";
std::cout << "Public key: " << oxenc::to_hex(pubkey.begin(), pubkey.end()) << "\n";
}
return 0;
@ -220,8 +220,8 @@ int show(std::list<std::string_view> args) {
pubkey = pubkey_from_privkey(seckey);
std::cout << filename.u8string() << " (legacy SN keypair)" << "\n==========" <<
"\nPrivate key: " << oxenmq::to_hex(seckey.begin(), seckey.begin() + 32) <<
"\nPublic key: " << oxenmq::to_hex(pubkey.begin(), pubkey.end()) << "\n\n";
"\nPrivate key: " << oxenc::to_hex(seckey.begin(), seckey.begin() + 32) <<
"\nPublic key: " << oxenc::to_hex(pubkey.begin(), pubkey.end()) << "\n\n";
return 0;
}
@ -234,16 +234,16 @@ int show(std::list<std::string_view> args) {
ustring_view privkey{privkey_signhash.data(), 32};
pubkey = pubkey_from_privkey(privkey);
if (size >= 64 && ustring_view{pubkey.data(), pubkey.size()} != ustring_view{seckey.data() + 32, 32})
return error(13, "Error: derived pubkey (" + oxenmq::to_hex(pubkey.begin(), pubkey.end()) + ")"
" != embedded pubkey (" + oxenmq::to_hex(seckey.begin() + 32, seckey.end()) + ")");
return error(13, "Error: derived pubkey (" + oxenc::to_hex(pubkey.begin(), pubkey.end()) + ")"
" != embedded pubkey (" + oxenc::to_hex(seckey.begin() + 32, seckey.end()) + ")");
if (0 != crypto_sign_ed25519_pk_to_curve25519(x_pubkey.data(), pubkey.data()))
return error(14, "Unable to convert Ed25519 pubkey to X25519 pubkey; is this a really valid secret key?");
std::cout << filename << " (Ed25519 SN keypair)" << "\n==========" <<
"\nSecret key: " << oxenmq::to_hex(seckey.begin(), seckey.begin() + 32) <<
"\nPublic key: " << oxenmq::to_hex(pubkey.begin(), pubkey.end()) <<
"\nX25519 pubkey: " << oxenmq::to_hex(x_pubkey.begin(), x_pubkey.end()) <<
"\nLokinet address: " << oxenmq::to_base32z(pubkey.begin(), pubkey.end()) << ".snode\n\n";
"\nSecret key: " << oxenc::to_hex(seckey.begin(), seckey.begin() + 32) <<
"\nPublic key: " << oxenc::to_hex(pubkey.begin(), pubkey.end()) <<
"\nX25519 pubkey: " << oxenc::to_hex(x_pubkey.begin(), x_pubkey.end()) <<
"\nLokinet address: " << oxenc::to_base32z(pubkey.begin(), pubkey.end()) << ".snode\n\n";
return 0;
}
@ -278,15 +278,15 @@ int restore(bool ed25519, std::list<std::string_view> args) {
// Advanced feature: if you provide the concatenated privkey and pubkey in hex, we won't prompt
// for verification (as long as the pubkey matches what we derive from the privkey).
if (!(skey_hex.size() == 64 || skey_hex.size() == 128) || !oxenmq::is_hex(skey_hex))
if (!(skey_hex.size() == 64 || skey_hex.size() == 128) || !oxenc::is_hex(skey_hex))
return error(7, "Invalid input: provide the secret key as 64 hex characters");
std::array<unsigned char, crypto_sign_SECRETKEYBYTES> skey;
std::array<unsigned char, crypto_sign_PUBLICKEYBYTES> pubkey;
std::array<unsigned char, crypto_sign_SEEDBYTES> seed;
std::optional<std::array<unsigned char, crypto_sign_PUBLICKEYBYTES>> pubkey_expected;
oxenmq::from_hex(skey_hex.begin(), skey_hex.begin() + 64, seed.begin());
oxenc::from_hex(skey_hex.begin(), skey_hex.begin() + 64, seed.begin());
if (skey_hex.size() == 128)
oxenmq::from_hex(skey_hex.begin() + 64, skey_hex.end(), pubkey_expected.emplace().begin());
oxenc::from_hex(skey_hex.begin() + 64, skey_hex.end(), pubkey_expected.emplace().begin());
if (ed25519) {
crypto_sign_seed_keypair(pubkey.data(), skey.data(), seed.data());
@ -294,19 +294,19 @@ int restore(bool ed25519, std::list<std::string_view> args) {
pubkey = pubkey_from_privkey(seed);
}
std::cout << "\nPublic key: " << oxenmq::to_hex(pubkey.begin(), pubkey.end()) << "\n";
std::cout << "\nPublic key: " << oxenc::to_hex(pubkey.begin(), pubkey.end()) << "\n";
if (ed25519) {
std::array<unsigned char, crypto_scalarmult_curve25519_BYTES> x_pubkey;
if (0 != crypto_sign_ed25519_pk_to_curve25519(x_pubkey.data(), pubkey.data()))
return error(14, "Unable to convert Ed25519 pubkey to X25519 pubkey; is this a really valid secret key?");
std::cout << "X25519 pubkey: " << oxenmq::to_hex(x_pubkey.begin(), x_pubkey.end()) <<
"\nLokinet address: " << oxenmq::to_base32z(pubkey.begin(), pubkey.end()) << ".snode";
std::cout << "X25519 pubkey: " << oxenc::to_hex(x_pubkey.begin(), x_pubkey.end()) <<
"\nLokinet address: " << oxenc::to_base32z(pubkey.begin(), pubkey.end()) << ".snode";
}
if (pubkey_expected) {
if (*pubkey_expected != pubkey)
return error(2, "Derived pubkey (" + oxenmq::to_hex(pubkey.begin(), pubkey.end()) + ") doesn't match "
"provided pubkey (" + oxenmq::to_hex(pubkey_expected->begin(), pubkey_expected->end()) + ")");
return error(2, "Derived pubkey (" + oxenc::to_hex(pubkey.begin(), pubkey.end()) + ") doesn't match "
"provided pubkey (" + oxenc::to_hex(pubkey_expected->begin(), pubkey_expected->end()) + ")");
} else {
if (ed25519 && filename.size() >= 4 && filename.substr(filename.size() - 4) == "/key") {
@ -324,7 +324,7 @@ int restore(bool ed25519, std::list<std::string_view> args) {
}
if (pubkey_pos != std::string::npos)
filename.replace(pubkey_pos, 6, oxenmq::to_hex(pubkey.begin(), pubkey.end()));
filename.replace(pubkey_pos, 6, oxenc::to_hex(pubkey.begin(), pubkey.end()));
auto filepath = fs::u8path(filename);
if (!overwrite && fs::exists(filepath))

View File

@ -75,10 +75,10 @@ namespace cryptonote
{
crypto::hash result = crypto::null_hash;
*height = 0;
if (nettype != MAINNET && nettype != TESTNET)
if (nettype != network_type::MAINNET && nettype != network_type::TESTNET)
return result;
if (nettype == MAINNET)
if (nettype == network_type::MAINNET)
{
uint64_t last_index = oxen::array_count(HARDCODED_MAINNET_CHECKPOINTS) - 1;
height_to_hash const &entry = HARDCODED_MAINNET_CHECKPOINTS[last_index];
@ -170,7 +170,7 @@ namespace cryptonote
bool checkpoints::block_added(const cryptonote::block& block, const std::vector<cryptonote::transaction>& txs, checkpoint_t const *checkpoint)
{
uint64_t const height = get_block_height(block);
if (height < service_nodes::CHECKPOINT_STORE_PERSISTENTLY_INTERVAL || block.major_version < network_version_12_checkpointing)
if (height < service_nodes::CHECKPOINT_STORE_PERSISTENTLY_INTERVAL || block.major_version < hf::hf12_checkpointing)
return true;
uint64_t end_cull_height = 0;
@ -308,12 +308,13 @@ namespace cryptonote
if (db->is_read_only())
return true;
if (nettype == MAINNET)
if (nettype == network_type::MAINNET)
{
for (size_t i = 0; i < oxen::array_count(HARDCODED_MAINNET_CHECKPOINTS); ++i)
{
height_to_hash const &checkpoint = HARDCODED_MAINNET_CHECKPOINTS[i];
ADD_CHECKPOINT(checkpoint.height, checkpoint.hash);
bool added = add_checkpoint(checkpoint.height, checkpoint.hash);
CHECK_AND_ASSERT(added, false);
}
}

View File

@ -38,11 +38,11 @@
#include "cryptonote_basic/cryptonote_basic_impl.h"
#include "common/fs.h"
#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false);
#define JSON_HASH_FILE_NAME "checkpoints.json"
namespace cryptonote
{
constexpr std::string_view JSON_HASH_FILE_NAME = "checkpoints.json"sv;
enum struct checkpoint_type
{
hardcoded,
@ -197,7 +197,7 @@ namespace cryptonote
bool init(network_type nettype, class BlockchainDB *db);
private:
network_type m_nettype = UNDEFINED;
network_type m_nettype = network_type::UNDEFINED;
uint64_t m_last_cull_height = 0;
uint64_t m_immutable_height = 0;
BlockchainDB *m_db;

View File

@ -32,7 +32,6 @@ add_library(common
base58.cpp
combinator.cpp
command_line.cpp
dns_utils.cpp
error.cpp
expect.cpp
file.cpp
@ -70,7 +69,5 @@ target_link_libraries(common
date::date
fmt::fmt
PRIVATE
libunbound
OpenSSL::SSL
OpenSSL::Crypto
sodium
extra)

View File

@ -32,7 +32,6 @@
namespace tools
{
class DNSResolver;
struct login;
class password_container;
class t_http_connection;

View File

@ -1,670 +0,0 @@
// Copyright (c) 2014-2019, The Monero Project
// Copyright (c) 2018, The Loki 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 "common/dns_utils.h"
// check local first (in the event of static or in-source compilation of libunbound)
#include "common/string_util.h"
#include "unbound.h"
#include <chrono>
#include <optional>
#include <stdexcept>
#include <cstdlib>
#include <cstdio>
#include "epee/misc_log_ex.h"
#include "common/threadpool.h"
#include "crypto/crypto.h"
#undef OXEN_DEFAULT_LOG_CATEGORY
#define OXEN_DEFAULT_LOG_CATEGORY "net.dns"
using namespace std::literals;
static constexpr std::array DEFAULT_DNS_PUBLIC_ADDR =
{
"194.150.168.168"sv, // CCC (Germany)
"80.67.169.40"sv, // FDN (France)
"89.233.43.71"sv, // http://censurfridns.dk (Denmark)
"109.69.8.51"sv, // punCAT (Spain)
"193.58.251.251"sv, // SkyDNS (Russia)
};
namespace
{
/*
* The following two functions were taken from unbound-anchor.c, from
* the unbound library packaged with this source. The license and source
* can be found in $PROJECT_ROOT/external/unbound
*/
/* Cert builtin commented out until it's used, as the compiler complains
// return the built in root update certificate
static const char*
get_builtin_cert(void)
{
return
// The ICANN CA fetched at 24 Sep 2010. Valid to 2028
"-----BEGIN CERTIFICATE-----\n"
"MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n"
"TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n"
"BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX\n"
"DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O\n"
"IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB\n"
"MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb\n"
"cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S\n"
"G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg\n"
"ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2\n"
"paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7\n"
"MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29\n"
"iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
"Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3\n"
"DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH\n"
"6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD\n"
"2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h\n"
"15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n"
"0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n"
"j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n"
"-----END CERTIFICATE-----\n"
;
}
*/
/** return the built in root DS trust anchor */
constexpr auto get_builtin_ds()
{
return std::array{
". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5\n",
". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D\n",
};
}
/************************************************************
************************************************************
***********************************************************/
} // anonymous namespace
namespace tools
{
static constexpr const char *get_record_name(int record_type)
{
switch (record_type)
{
case DNS_TYPE_A: return "A";
case DNS_TYPE_TXT: return "TXT";
case DNS_TYPE_AAAA: return "AAAA";
default: return "unknown";
}
}
// fuck it, I'm tired of dealing with getnameinfo()/inet_ntop/etc
std::optional<std::string> ipv4_to_string(const char* src, size_t len)
{
if (len < 4)
{
MERROR("Invalid IPv4 address: " << std::string(src, len));
return std::nullopt;
}
std::stringstream ss;
unsigned int bytes[4];
for (int i = 0; i < 4; i++)
{
unsigned char a = src[i];
bytes[i] = a;
}
ss << bytes[0] << "."
<< bytes[1] << "."
<< bytes[2] << "."
<< bytes[3];
return ss.str();
}
// this obviously will need to change, but is here to reflect the above
// stop-gap measure and to make the tests pass at least...
std::optional<std::string> ipv6_to_string(const char* src, size_t len)
{
if (len < 8)
{
MERROR("Invalid IPv4 address: " << std::string(src, len));
return std::nullopt;
}
std::stringstream ss;
unsigned int bytes[8];
for (int i = 0; i < 8; i++)
{
unsigned char a = src[i];
bytes[i] = a;
}
ss << bytes[0] << ":"
<< bytes[1] << ":"
<< bytes[2] << ":"
<< bytes[3] << ":"
<< bytes[4] << ":"
<< bytes[5] << ":"
<< bytes[6] << ":"
<< bytes[7];
return ss.str();
}
std::optional<std::string> txt_to_string(const char* src, size_t len)
{
if (len == 0)
return std::nullopt;
return std::string(src+1, len-1);
}
void ub_ctx_deleter::operator()(ub_ctx* ctx) {
ub_ctx_delete(ctx);
}
namespace {
struct ub_result_deleter {
void operator()(ub_result* result) {
ub_resolve_free(result);
}
};
using ub_result_ptr = std::unique_ptr<ub_result, ub_result_deleter>;
void add_anchors(ub_ctx *ctx)
{
for (const char* ds : get_builtin_ds())
{
MINFO("adding trust anchor: " << *ds);
ub_ctx_add_ta(ctx, const_cast<char*>(ds));
}
}
} // anonymous namespace
DNSResolver::DNSResolver()
{
int use_dns_public = 0;
std::vector<std::string> dns_public_addr;
const char *DNS_PUBLIC = getenv("DNS_PUBLIC");
if (DNS_PUBLIC)
{
dns_public_addr = tools::dns_utils::parse_dns_public(DNS_PUBLIC);
if (!dns_public_addr.empty())
{
MGINFO("Using public DNS server(s): " << tools::join(", ", dns_public_addr) << " (TCP)");
use_dns_public = 1;
}
else
{
MERROR("Failed to parse DNS_PUBLIC");
}
}
// init libunbound context
m_ctx = ub_ctx_create();
if (use_dns_public)
{
for (const auto &ip: dns_public_addr)
ub_ctx_set_fwd(m_ctx, ip.c_str());
ub_ctx_set_option(m_ctx, "do-udp:", "no");
ub_ctx_set_option(m_ctx, "do-tcp:", "yes");
}
else {
// look for "/etc/resolv.conf" and "/etc/hosts" or platform equivalent
ub_ctx_resolvconf(m_ctx, NULL);
ub_ctx_hosts(m_ctx, NULL);
}
add_anchors(m_ctx);
if (!DNS_PUBLIC)
{
// TODO(oxen): Don't probe moneropulse for Loki
#if 0
// if no DNS_PUBLIC specified, we try a lookup to what we know
// should be a valid DNSSEC record, and switch to known good
// DNSSEC resolvers if verification fails
bool available, valid;
static const char *probe_hostname = "updates.moneropulse.org";
auto records = get_txt_record(probe_hostname, available, valid);
if (!valid)
{
MINFO("Failed to verify DNSSEC record from " << probe_hostname << ", falling back to TCP with well known DNSSEC resolvers");
ub_ctx_delete(m_ctx);
m_ctx = ub_ctx_create();
add_anchors(m_ctx);
for (const auto &ip: DEFAULT_DNS_PUBLIC_ADDR)
ub_ctx_set_fwd(m_ctx, string_copy(ip));
ub_ctx_set_option(m_ctx, string_copy("do-udp:"), string_copy("no"));
ub_ctx_set_option(m_ctx, string_copy("do-tcp:"), string_copy("yes"));
}
#endif
}
}
std::vector<std::string> DNSResolver::get_record(const std::string& url, int record_type, std::optional<std::string> (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid)
{
std::vector<std::string> addresses;
dnssec_available = false;
dnssec_valid = false;
if (url.find('.') == std::string::npos)
{
return addresses;
}
ub_result* result_raw = nullptr;
// call DNS resolver, blocking. if return value not zero, something went wrong
if (!ub_resolve(m_ctx, url.c_str(), record_type, DNS_CLASS_IN, &result_raw))
{
// destructor takes care of cleanup
ub_result_ptr result{result_raw};
dnssec_available = (result->secure || result->bogus);
dnssec_valid = result->secure && !result->bogus;
if (result->havedata)
{
for (size_t i=0; result->data[i] != NULL; i++)
{
if (auto res = (*reader)(result->data[i], result->len[i]))
{
MINFO("Found \"" << *res << "\" in " << get_record_name(record_type) << " record for " << url);
addresses.push_back(*res);
}
}
}
}
return addresses;
}
std::vector<std::string> DNSResolver::get_ipv4(const std::string& url, bool& dnssec_available, bool& dnssec_valid)
{
return get_record(url, DNS_TYPE_A, ipv4_to_string, dnssec_available, dnssec_valid);
}
std::vector<std::string> DNSResolver::get_ipv6(const std::string& url, bool& dnssec_available, bool& dnssec_valid)
{
return get_record(url, DNS_TYPE_AAAA, ipv6_to_string, dnssec_available, dnssec_valid);
}
std::vector<std::string> DNSResolver::get_txt_record(const std::string& url, bool& dnssec_available, bool& dnssec_valid)
{
return get_record(url, DNS_TYPE_TXT, txt_to_string, dnssec_available, dnssec_valid);
}
namespace {
// Data pack that we pass into the unbound callback:
struct dns_results {
int& all_done;
const std::string& hostname;
const char* record_name;
std::vector<std::string>& results;
std::optional<std::string> (*reader)(const char*, size_t);
int async_id{0};
bool done{false};
bool dnssec;
bool dnssec_required;
dns_results(int& a, const std::string& h, const char* rn, std::vector<std::string>& r, std::optional<std::string> (*rdr)(const char*, size_t), bool dnssec, bool dnssec_req)
: all_done{a}, hostname{h}, record_name{rn}, results{r}, reader{rdr}, dnssec{dnssec}, dnssec_required{dnssec_req}
{}
};
}
extern "C" void DNSResolver_async_callback(void* data, int err, ub_result* result_raw)
{
ub_result_ptr result{result_raw};
auto &res = *static_cast<dns_results*>(data);
res.all_done++;
res.done = true;
if (err)
MWARNING("resolution of " << res.hostname << " failed: " << ub_strerror(err));
else if ((res.dnssec || res.dnssec_required) && result->bogus)
MWARNING("resolution of " << res.hostname << " failed DNSSEC validation: " << result->why_bogus);
else if (res.dnssec_required && !result->secure)
MWARNING("resolution of " << res.hostname << " failed: DNSSEC validate is required but is not available");
else if (result->havedata)
{
for (size_t i = 0; result->data[i] != NULL; i++)
{
if (auto r = (*res.reader)(result->data[i], result->len[i]))
{
MINFO("Found \"" << *r << "\" in " << res.record_name << " record for " << res.hostname);
res.results.push_back(*r);
}
}
}
}
std::vector<std::vector<std::string>> DNSResolver::get_many(int type, const std::vector<std::string>& hostnames, std::chrono::milliseconds timeout, bool dnssec, bool dnssec_required)
{
auto* reader = type == DNS_TYPE_A ? ipv4_to_string : type == DNS_TYPE_AAAA ? ipv6_to_string : type == DNS_TYPE_TXT ? txt_to_string : nullptr;
if (!reader)
throw std::invalid_argument("Invalid lookup type: " + std::to_string(type));
std::vector<std::vector<std::string>> results;
if (hostnames.empty())
return results;
int num_done = 0;
std::vector<dns_results> result_packs;
results.reserve(hostnames.size());
result_packs.reserve(hostnames.size());
ub_ctx_async(m_ctx, true); // Tells libunbound to use a thread instead of a fork
// Initiate lookups:
for (auto& host : hostnames)
{
auto& pack = result_packs.emplace_back(num_done, host, get_record_name(type), results.emplace_back(), reader, dnssec, dnssec_required);
int err = ub_resolve_async(m_ctx, host.c_str(), type, DNS_CLASS_IN, static_cast<void*>(&pack), DNSResolver_async_callback, &pack.async_id);
if (err)
{
MWARNING("unable to initiate lookup for " << host << ": " << ub_strerror(err));
num_done++;
pack.done = true;
}
}
// Wait for results
auto expiry = std::chrono::steady_clock::now() + timeout;
while (num_done < (int)results.size() && std::chrono::steady_clock::now() < expiry)
{
std::this_thread::sleep_for(5ms);
int err = ub_process(m_ctx);
if (err)
{
MWARNING("ub_process returned an error while waiting for async results: " << ub_strerror(err));
break;
}
}
// Cancel any outstanding requests
for (auto& pack : result_packs)
{
if (!pack.done)
ub_cancel(m_ctx, pack.async_id);
}
return results;
}
std::string DNSResolver::get_dns_format_from_oa_address(std::string_view addr_v)
{
std::string addr{addr_v};
auto first_at = addr.find("@");
if (first_at == std::string::npos)
return addr;
// convert name@domain.tld to name.domain.tld
addr.replace(first_at, 1, ".");
return addr;
}
DNSResolver& DNSResolver::instance()
{
static DNSResolver staticInstance;
return staticInstance;
}
DNSResolver DNSResolver::create()
{
return DNSResolver();
}
namespace dns_utils
{
//-----------------------------------------------------------------------
// TODO: parse the string in a less stupid way, probably with regex
std::string address_from_txt_record(std::string_view s)
{
// make sure the txt record has the addr_type and find it
constexpr auto addr_type = "oa1:xmr"sv;
if (auto pos = s.find(addr_type); pos != std::string_view::npos)
s.remove_prefix(pos + addr_type.size()); // remove it and everything before it
else
return {}; // not found.
constexpr auto recipient_address = "recipient_address="sv;
if (auto pos = s.find(recipient_address); pos != std::string_view::npos)
s.remove_prefix(pos + recipient_address.size()); // delete it and everything up to it
else
return {}; // not found
// find the next semicolon
if (auto pos = s.find(';'); pos != std::string::npos)
{
// length of address == 95, we can at least validate that much here
if (pos == 95)
return std::string{s.substr(0, 95)};
else if (pos == 106) // length of address == 106 --> integrated address
return std::string{s.substr(0, 106)};
}
return {};
}
/**
* @brief gets a oxen address from the TXT record of a DNS entry
*
* gets the oxen address from the TXT record of the DNS entry associated
* with <url>. If this lookup fails, or the TXT record does not contain an
* XMR address in the correct format, returns an empty string. <dnssec_valid>
* will be set true or false according to whether or not the DNS query passes
* DNSSEC validation.
*
* @param url the url to look up
* @param dnssec_valid return-by-reference for DNSSEC status of query
*
* @return a oxen address (as a string) or an empty string
*/
std::vector<std::string> addresses_from_url(const std::string_view url, bool& dnssec_valid)
{
std::vector<std::string> addresses;
// get txt records
bool dnssec_available, dnssec_isvalid;
std::string oa_addr = DNSResolver::instance().get_dns_format_from_oa_address(url);
auto records = DNSResolver::instance().get_txt_record(oa_addr, dnssec_available, dnssec_isvalid);
// TODO: update this to allow for conveying that dnssec was not available
if (dnssec_available && dnssec_isvalid)
{
dnssec_valid = true;
}
else dnssec_valid = false;
// for each txt record, try to find a oxen address in it.
for (auto& rec : records)
{
std::string addr = address_from_txt_record(rec);
if (addr.size())
{
addresses.push_back(std::move(addr));
}
}
return addresses;
}
std::string get_account_address_as_str_from_url(const std::string_view url, bool& dnssec_valid,
std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm)
{
// attempt to get address from dns query
auto addresses = addresses_from_url(url, dnssec_valid);
if (addresses.empty())
{
LOG_ERROR("wrong address: " << url);
return {};
}
return dns_confirm(url, addresses, dnssec_valid);
}
namespace
{
bool dns_records_match(const std::vector<std::string>& a, const std::vector<std::string>& b)
{
if (a.size() != b.size()) return false;
for (const auto& record_in_a : a)
{
bool ok = false;
for (const auto& record_in_b : b)
{
if (record_in_a == record_in_b)
{
ok = true;
break;
}
}
if (!ok) return false;
}
return true;
}
}
bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std::vector<std::string> &dns_urls)
{
// Prevent infinite recursion when distributing
if (dns_urls.empty()) return false;
std::vector<std::vector<std::string> > records;
records.resize(dns_urls.size());
size_t first_index = crypto::rand_idx(dns_urls.size());
// send all requests in parallel
std::deque<bool> avail(dns_urls.size(), false), valid(dns_urls.size(), false);
tools::threadpool& tpool = tools::threadpool::getInstance();
tools::threadpool::waiter waiter;
for (size_t n = 0; n < dns_urls.size(); ++n)
{
tpool.submit(&waiter,[n, dns_urls, &records, &avail, &valid](){
records[n] = tools::DNSResolver::instance().get_txt_record(dns_urls[n], avail[n], valid[n]);
});
}
waiter.wait(&tpool);
size_t cur_index = first_index;
do
{
const std::string &url = dns_urls[cur_index];
if (!avail[cur_index])
{
records[cur_index].clear();
LOG_PRINT_L2("DNSSEC not available for hostname: " << url << ", skipping.");
}
if (!valid[cur_index])
{
records[cur_index].clear();
LOG_PRINT_L2("DNSSEC validation failed for hostname: " << url << ", skipping.");
}
cur_index++;
if (cur_index == dns_urls.size())
{
cur_index = 0;
}
} while (cur_index != first_index);
size_t num_valid_records = 0;
for( const auto& record_set : records)
{
if (record_set.size() != 0)
{
num_valid_records++;
}
}
if (num_valid_records < 2)
{
LOG_PRINT_L0("WARNING: no two valid DNS TXT records were received");
return false;
}
int good_records_index = -1;
for (size_t i = 0; i < records.size() - 1; ++i)
{
if (records[i].size() == 0) continue;
for (size_t j = i + 1; j < records.size(); ++j)
{
if (dns_records_match(records[i], records[j]))
{
good_records_index = i;
break;
}
}
if (good_records_index >= 0) break;
}
if (good_records_index < 0)
{
LOG_PRINT_L0("WARNING: no two DNS TXT records matched");
return false;
}
good_records = records[good_records_index];
return true;
}
std::vector<std::string> parse_dns_public(const char *s)
{
unsigned ip0, ip1, ip2, ip3;
char c;
std::vector<std::string> dns_public_addr;
if (s == "tcp"sv)
{
for (auto& default_dns : DEFAULT_DNS_PUBLIC_ADDR)
dns_public_addr.emplace_back(default_dns);
LOG_PRINT_L0("Using default public DNS server(s): " << tools::join(", ", dns_public_addr) << " (TCP)");
}
else if (std::sscanf(s, "tcp://%u.%u.%u.%u%c", &ip0, &ip1, &ip2, &ip3, &c) == 4)
{
if (ip0 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255)
{
MERROR("Invalid IP: " << s << ", using default");
}
else
{
dns_public_addr.emplace_back(s + 6);
}
}
else
{
MERROR("Invalid DNS_PUBLIC contents, ignored");
}
return dns_public_addr;
}
} // namespace tools::dns_utils
} // namespace tools

View File

@ -1,186 +0,0 @@
// Copyright (c) 2014-2019, 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.
#pragma once
#include <vector>
#include <string>
#include <functional>
#include <optional>
#include <chrono>
#include <string_view>
struct ub_ctx;
namespace tools
{
using namespace std::literals;
// RFC defines for record types and classes for DNS, gleaned from ldns source
constexpr int DNS_CLASS_IN = 1;
constexpr int DNS_TYPE_A = 1;
constexpr int DNS_TYPE_TXT = 16;
constexpr int DNS_TYPE_AAAA = 8;
struct ub_ctx_deleter { void operator()(ub_ctx*); };
/**
* @brief Provides high-level access to DNS resolution
*
* This class is designed to provide a high-level abstraction to DNS resolution
* functionality, including access to TXT records and such. It will also
* handle DNSSEC validation of the results.
*/
class DNSResolver
{
private:
/**
* @brief Constructs an instance of DNSResolver
*
* Constructs a class instance and does setup stuff for the backend resolver.
*/
DNSResolver();
public:
/**
* @brief gets ipv4 addresses from DNS query of a URL
*
* returns a vector of all IPv4 "A" records for given URL.
* If no "A" records found, returns an empty vector.
*
* @param url A string containing a URL to query for
*
* @param dnssec_available
*
* @return vector of strings containing ipv4 addresses
*/
std::vector<std::string> get_ipv4(const std::string& url, bool& dnssec_available, bool& dnssec_valid);
/**
* @brief gets ipv6 addresses from DNS query
*
* returns a vector of all IPv6 "A" records for given URL.
* If no "A" records found, returns an empty vector.
*
* @param url A string containing a URL to query for
*
* @return vector of strings containing ipv6 addresses
*/
std::vector<std::string> get_ipv6(const std::string& url, bool& dnssec_available, bool& dnssec_valid);
/**
* @brief gets all TXT records from a DNS query for the supplied URL;
* if no TXT record present returns an empty vector.
*
* @param url A string containing a URL to query for
*
* @return A vector of strings containing a TXT record; or an empty vector
*/
// TODO: modify this to accommodate DNSSEC
std::vector<std::string> get_txt_record(const std::string& url, bool& dnssec_available, bool& dnssec_valid);
/**
* @brief query multiple hostnames simultaneously for results, waiting up to a fixed amount of
* time for results before returning.
*
* @param type `DNS_TYPE_A` or `DNS_TYPE_AAAA` or `DNS_TYPE_TXT` indicating the lookup type.
* @param hostnames a vector of hostnames to look up
* @param timeout how long to wait for results before giving up. Any results not yet retrieved by
* the timeout are left empty.
* @param dnssec if true then validate DNSSEC if available (i.e. reject DNSSEC failures, but allow insecure results when DNSSEC not available)
* @param dnssec_required if true then require and validate DNSSEC (i.e. reject failures and reject when DNSSEC not available)
*
* Returns a vector of vector of results: the results for address [i] are in result element [i].
* If lookup failed (or DNSSEC failed with the relevant options given) for element [i] then vector
* [i] will be empty.
*/
// TODO: this could be extended to support doing multiple lookup types at once (e.g. A and AAAA).
std::vector<std::vector<std::string>> get_many(int type, const std::vector<std::string>& hostnames, std::chrono::milliseconds timeout = 10s, bool dnssec = false, bool dnssec_required = false);
/**
* @brief Gets a DNS address from OpenAlias format
*
* If the address looks good, but contains one @ symbol, replace that with a .
* e.g. donate@getmonero.org becomes donate.getmonero.org
*
* @param oa_addr OpenAlias address
*
* @return dns_addr DNS address
*/
std::string get_dns_format_from_oa_address(std::string_view oa_addr);
/**
* @brief Gets the singleton instance of DNSResolver
*
* @return returns a reference to the singleton
*/
static DNSResolver& instance();
/**
* @brief Gets a new instance of DNSResolver
*
* @return returns a pointer to the new object
*/
static DNSResolver create();
private:
/**
* @brief gets all records of a given type from a DNS query for the supplied URL;
* if no such record is present returns an empty vector.
*
* @param url A string containing a URL to query for
* @param record_type the record type to retrieve (DNS_TYPE_A, etc)
* @param reader a function that converts a record data to a string
*
* @return A vector of strings containing the requested record; or an empty vector
*/
// TODO: modify this to accommodate DNSSEC
std::vector<std::string> get_record(const std::string& url, int record_type, std::optional<std::string> (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid);
ub_ctx* m_ctx = nullptr;
}; // class DNSResolver
namespace dns_utils
{
std::string address_from_txt_record(std::string_view s);
std::vector<std::string> addresses_from_url(const std::string_view url, bool& dnssec_valid);
std::string get_account_address_as_str_from_url(const std::string_view url, bool& dnssec_valid,
std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> confirm_dns);
bool load_txt_records_from_dns(std::vector<std::string> &records, const std::vector<std::string> &dns_urls);
std::vector<std::string> parse_dns_public(const char *s);
} // namespace tools::dns_utils
} // namespace tools

View File

@ -254,7 +254,7 @@ namespace tools {
}
#ifdef WIN32
#ifdef _WIN32
fs::path get_special_folder_path(int nfolder, bool iscreate)
{
WCHAR psz_path[MAX_PATH] = L"";
@ -267,31 +267,29 @@ namespace tools {
LOG_ERROR("SHGetSpecialFolderPathW() failed, could not obtain requested path.");
return "";
}
// Windows < Vista: C:\Documents and Settings\Username\Application Data\CRYPTONOTE_NAME
// Windows >= Vista: C:\Users\Username\AppData\Roaming\CRYPTONOTE_NAME
fs::path get_default_data_dir()
{
return get_special_folder_path(CSIDL_COMMON_APPDATA, true) / fs::u8path(CRYPTONOTE_NAME);
}
fs::path get_depreciated_default_data_dir()
{
return get_special_folder_path(CSIDL_COMMON_APPDATA, true) / fs::u8path("loki");
}
#else
// Non-windows: ~/.CRYPTONOTE_NAME
fs::path get_default_data_dir()
{
char* home = std::getenv("HOME");
return (home && std::strlen(home) ? fs::u8path(home) : fs::current_path()) / fs::u8path("." CRYPTONOTE_NAME);
}
fs::path get_depreciated_default_data_dir()
{
char* home = std::getenv("HOME");
return (home && std::strlen(home) ? fs::u8path(home) : fs::current_path()) / fs::u8path(".loki");
}
#endif
// Windows < Vista: C:\Documents and Settings\Username\Application Data\...
// Windows >= Vista: C:\Users\Username\AppData\Roaming\...
// Sane OSes: ~/
static fs::path get_default_parent_dir() {
#ifdef _WIN32
return get_special_folder_path(CSIDL_COMMON_APPDATA, true);
#else
char* home = std::getenv("HOME");
return home && std::strlen(home) ? fs::u8path(home) : fs::current_path();
#endif
}
fs::path get_default_data_dir()
{
return get_default_parent_dir() / fs::u8path(cryptonote::DATA_DIRNAME);
}
fs::path get_depreciated_default_data_dir()
{
return get_default_parent_dir() / fs::u8path(cryptonote::old::DATA_DIRNAME);
}
void set_strict_default_file_permissions(bool strict)
{
#if defined(__MINGW32__) || defined(__MINGW__)

View File

@ -1,5 +1,5 @@
#pragma once
#include <oxenmq/hex.h>
#include <oxenc/hex.h>
#include <type_traits>
#include "epee/span.h" // epee
@ -11,9 +11,9 @@ namespace tools {
!std::is_const_v<T> && (std::is_trivially_copyable_v<T> || epee::is_byte_spannable<T>)
>>
bool hex_to_type(std::string_view hex, T& x) {
if (!oxenmq::is_hex(hex) || hex.size() != 2*sizeof(T))
if (!oxenc::is_hex(hex) || hex.size() != 2*sizeof(T))
return false;
oxenmq::from_hex(hex.begin(), hex.end(), reinterpret_cast<char*>(&x));
oxenc::from_hex(hex.begin(), hex.end(), reinterpret_cast<char*>(&x));
return true;
}
@ -23,6 +23,6 @@ namespace tools {
|| epee::is_byte_spannable<T>
>>
std::string type_to_hex(const T& val) {
return oxenmq::to_hex(std::string_view{reinterpret_cast<const char*>(&val), sizeof(val)});
return oxenc::to_hex(std::string_view{reinterpret_cast<const char*>(&val), sizeof(val)});
}
}

33
src/common/median.h Normal file
View File

@ -0,0 +1,33 @@
// Copyright (c) 2022, The Oxen Project
#include <algorithm>
#include <vector>
namespace tools {
// Calculate the median element (the middle element, if an odd size, and the mean of the two
// middle elements if even). Pass first=true if you don't care about the mean of the middle two,
// in which case you'll get back the value of lower of the two middle elements.
// This leaves the given range in an indeterminant (partially sorted) order.
template <typename RandomAccessIter>
auto median(RandomAccessIter begin, RandomAccessIter end, bool first=false) {
std::size_t size = end - begin;
if (size == 0)
return std::decay_t<decltype(*begin)>{};
auto mid = begin + (size - 1) / 2;
std::nth_element(begin, mid, end);
if (first || size % 2)
return *mid;
auto mid2 = std::min_element(mid + 1, end);
return (*mid + *mid2) / 2;
}
// Same as above, but takes a vector by value or move for convenience.
template <typename T>
T median(std::vector<T> v, bool first=false) {
return median(v.begin(), v.end(), first);
}
}

View File

@ -34,6 +34,8 @@
namespace tools
{
using namespace cryptonote;
uint32_t make_pruning_seed(uint32_t stripe, uint32_t log_stripes)
{
CHECK_AND_ASSERT_THROW_MES(log_stripes <= PRUNING_SEED_LOG_STRIPES_MASK, "log_stripes out of range");
@ -53,9 +55,9 @@ bool has_unpruned_block(uint64_t block_height, uint64_t blockchain_height, uint3
uint32_t get_pruning_stripe(uint64_t block_height, uint64_t blockchain_height, uint32_t log_stripes)
{
if (block_height + CRYPTONOTE_PRUNING_TIP_BLOCKS >= blockchain_height)
if (block_height + PRUNING_TIP_BLOCKS >= blockchain_height)
return 0;
return ((block_height / CRYPTONOTE_PRUNING_STRIPE_SIZE) & (uint64_t)((1ul << log_stripes) - 1)) + 1;
return ((block_height / PRUNING_STRIPE_SIZE) & (uint64_t)((1ul << log_stripes) - 1)) + 1;
}
uint32_t get_pruning_seed(uint64_t block_height, uint64_t blockchain_height, uint32_t log_stripes)
@ -68,24 +70,24 @@ uint32_t get_pruning_seed(uint64_t block_height, uint64_t blockchain_height, uin
uint64_t get_next_unpruned_block_height(uint64_t block_height, uint64_t blockchain_height, uint32_t pruning_seed)
{
CHECK_AND_ASSERT_MES(block_height <= CRYPTONOTE_MAX_BLOCK_NUMBER+1, block_height, "block_height too large");
CHECK_AND_ASSERT_MES(blockchain_height <= CRYPTONOTE_MAX_BLOCK_NUMBER+1, block_height, "blockchain_height too large");
CHECK_AND_ASSERT_MES(block_height <= MAX_BLOCK_NUMBER+1, block_height, "block_height too large");
CHECK_AND_ASSERT_MES(blockchain_height <= MAX_BLOCK_NUMBER+1, block_height, "blockchain_height too large");
const uint32_t stripe = get_pruning_stripe(pruning_seed);
if (stripe == 0)
return block_height;
if (block_height + CRYPTONOTE_PRUNING_TIP_BLOCKS >= blockchain_height)
if (block_height + PRUNING_TIP_BLOCKS >= blockchain_height)
return block_height;
const uint32_t seed_log_stripes = get_pruning_log_stripes(pruning_seed);
const uint64_t log_stripes = seed_log_stripes ? seed_log_stripes : CRYPTONOTE_PRUNING_LOG_STRIPES;
const uint64_t log_stripes = seed_log_stripes ? seed_log_stripes : PRUNING_LOG_STRIPES;
const uint64_t mask = (1ul << log_stripes) - 1;
const uint32_t block_pruning_stripe = ((block_height / CRYPTONOTE_PRUNING_STRIPE_SIZE) & mask) + 1;
const uint32_t block_pruning_stripe = ((block_height / PRUNING_STRIPE_SIZE) & mask) + 1;
if (block_pruning_stripe == stripe)
return block_height;
const uint64_t cycles = ((block_height / CRYPTONOTE_PRUNING_STRIPE_SIZE) >> log_stripes);
const uint64_t cycles = ((block_height / PRUNING_STRIPE_SIZE) >> log_stripes);
const uint64_t cycle_start = cycles + ((stripe > block_pruning_stripe) ? 0 : 1);
const uint64_t h = cycle_start * (CRYPTONOTE_PRUNING_STRIPE_SIZE << log_stripes) + (stripe - 1) * CRYPTONOTE_PRUNING_STRIPE_SIZE;
if (h + CRYPTONOTE_PRUNING_TIP_BLOCKS > blockchain_height)
return blockchain_height < CRYPTONOTE_PRUNING_TIP_BLOCKS ? 0 : blockchain_height - CRYPTONOTE_PRUNING_TIP_BLOCKS;
const uint64_t h = cycle_start * (PRUNING_STRIPE_SIZE << log_stripes) + (stripe - 1) * PRUNING_STRIPE_SIZE;
if (h + PRUNING_TIP_BLOCKS > blockchain_height)
return blockchain_height < PRUNING_TIP_BLOCKS ? 0 : blockchain_height - PRUNING_TIP_BLOCKS;
CHECK_AND_ASSERT_MES(h >= block_height, block_height, "h < block_height, unexpected");
return h;
}
@ -95,12 +97,12 @@ uint64_t get_next_pruned_block_height(uint64_t block_height, uint64_t blockchain
const uint32_t stripe = get_pruning_stripe(pruning_seed);
if (stripe == 0)
return blockchain_height;
if (block_height + CRYPTONOTE_PRUNING_TIP_BLOCKS >= blockchain_height)
if (block_height + PRUNING_TIP_BLOCKS >= blockchain_height)
return blockchain_height;
const uint32_t seed_log_stripes = get_pruning_log_stripes(pruning_seed);
const uint64_t log_stripes = seed_log_stripes ? seed_log_stripes : CRYPTONOTE_PRUNING_LOG_STRIPES;
const uint64_t log_stripes = seed_log_stripes ? seed_log_stripes : PRUNING_LOG_STRIPES;
const uint64_t mask = (1ul << log_stripes) - 1;
const uint32_t block_pruning_seed = ((block_height / CRYPTONOTE_PRUNING_STRIPE_SIZE) & mask) + 1;
const uint32_t block_pruning_seed = ((block_height / PRUNING_STRIPE_SIZE) & mask) + 1;
if (block_pruning_seed != stripe)
return block_height;
const uint32_t next_stripe = 1 + (block_pruning_seed & mask);
@ -109,7 +111,7 @@ uint64_t get_next_pruned_block_height(uint64_t block_height, uint64_t blockchain
uint32_t get_random_stripe()
{
return 1 + crypto::rand<uint8_t>() % (1ul << CRYPTONOTE_PRUNING_LOG_STRIPES);
return 1 + crypto::rand<uint8_t>() % (1ul << PRUNING_LOG_STRIPES);
}
}

View File

@ -32,13 +32,19 @@
namespace tools
{
static constexpr uint32_t PRUNING_SEED_LOG_STRIPES_SHIFT = 7;
static constexpr uint32_t PRUNING_SEED_LOG_STRIPES_MASK = 0x7;
static constexpr uint32_t PRUNING_SEED_STRIPE_SHIFT = 0;
static constexpr uint32_t PRUNING_SEED_STRIPE_MASK = 0x7f;
inline constexpr uint32_t PRUNING_SEED_LOG_STRIPES_SHIFT = 7;
inline constexpr uint32_t PRUNING_SEED_LOG_STRIPES_MASK = 0x7;
inline constexpr uint32_t PRUNING_SEED_STRIPE_SHIFT = 0;
inline constexpr uint32_t PRUNING_SEED_STRIPE_MASK = 0x7f;
constexpr inline uint32_t get_pruning_log_stripes(uint32_t pruning_seed) { return (pruning_seed >> PRUNING_SEED_LOG_STRIPES_SHIFT) & PRUNING_SEED_LOG_STRIPES_MASK; }
inline uint32_t get_pruning_stripe(uint32_t pruning_seed) { if (pruning_seed == 0) return 0; return 1 + ((pruning_seed >> PRUNING_SEED_STRIPE_SHIFT) & PRUNING_SEED_STRIPE_MASK); }
inline constexpr uint32_t get_pruning_log_stripes(uint32_t pruning_seed) {
return (pruning_seed >> PRUNING_SEED_LOG_STRIPES_SHIFT) & PRUNING_SEED_LOG_STRIPES_MASK;
}
inline constexpr uint32_t get_pruning_stripe(uint32_t pruning_seed) {
if (pruning_seed == 0)
return 0;
return 1 + ((pruning_seed >> PRUNING_SEED_STRIPE_SHIFT) & PRUNING_SEED_STRIPE_MASK);
}
uint32_t make_pruning_seed(uint32_t stripe, uint32_t log_stripes);

View File

@ -41,11 +41,11 @@ namespace rules
bool is_output_unlocked(uint64_t unlock_time, uint64_t height)
{
if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER)
if(unlock_time < MAX_BLOCK_NUMBER)
{
// ND: Instead of calling get_current_blockchain_height(), call m_db->height()
// directly as get_current_blockchain_height() locks the recursive mutex.
if(height - 1 + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS >= unlock_time)
if(height - 1 + LOCKED_TX_ALLOWED_DELTA_BLOCKS >= unlock_time)
return true;
else
return false;
@ -54,7 +54,7 @@ bool is_output_unlocked(uint64_t unlock_time, uint64_t height)
{
//interpret as time
uint64_t current_time = static_cast<uint64_t>(time(NULL));
if(current_time + tools::to_seconds(CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2) >= unlock_time)
if(current_time + tools::to_seconds(LOCKED_TX_ALLOWED_DELTA_BLOCKS * TARGET_BLOCK_TIME) >= unlock_time)
return true;
else
return false;

View File

@ -28,14 +28,11 @@
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
namespace cryptonote
{
#include <cstdint>
namespace rules
namespace cryptonote::rules
{
bool is_output_unlocked(uint64_t unlock_time, uint64_t height);
} // namespace rules
} // namespace cryptonote
} // namespace cryptonote::rules

View File

@ -3,22 +3,16 @@
#include <fstream>
#include "crypto/hash.h"
#include "fs.h"
extern "C" {
#include <openssl/sha.h>
}
#include <sodium/crypto_hash_sha256.h>
namespace tools {
bool sha256sum_str(std::string_view data, crypto::hash &hash)
{
SHA256_CTX ctx;
if (!SHA256_Init(&ctx))
return false;
if (!SHA256_Update(&ctx, data.data(), data.size()))
return false;
if (!SHA256_Final(reinterpret_cast<unsigned char*>(hash.data), &ctx))
return false;
crypto_hash_sha256(
reinterpret_cast<unsigned char*>(hash.data),
reinterpret_cast<const unsigned char*>(data.data()),
data.size());
return true;
}
@ -32,25 +26,23 @@ namespace tools {
if (!f)
return false;
std::ifstream::pos_type file_size = f.tellg();
SHA256_CTX ctx;
if (!SHA256_Init(&ctx))
return false;
crypto_hash_sha256_state st;
crypto_hash_sha256_init(&st);
size_t size_left = file_size;
f.seekg(0, std::ios::beg);
std::array<unsigned char, 16384> buf;
while (size_left)
{
char buf[4096];
std::ifstream::pos_type read_size = size_left > sizeof(buf) ? sizeof(buf) : size_left;
f.read(buf, read_size);
auto read_size = std::min(size_left, buf.size());
f.read(reinterpret_cast<char*>(buf.data()), read_size);
if (!f || !f.good())
return false;
if (!SHA256_Update(&ctx, buf, read_size))
return false;
crypto_hash_sha256_update(&st, buf.data(), read_size);
size_left -= read_size;
}
f.close();
if (!SHA256_Final((unsigned char*)hash.data, &ctx))
return false;
crypto_hash_sha256_final(&st, reinterpret_cast<unsigned char*>(hash.data));
return true;
}

View File

@ -8,13 +8,6 @@ namespace crypto { struct hash; }
namespace tools {
// This used to be really dangerously overloaded with very different purposes:
//bool sha256sum(const uint8_t* data, size_t len, crypto::hash& hash);
//bool sha256sum(const fs::path& filename, crypto::hash& hash);
// which is incredibly dangerous if you happen to have a string you want to hash and see that
// there is both a pointer+size and std::string overload. Renamed *both* of these to prevent any
// existing code from compiling.
// Calculates sha256 checksum of the given data
bool sha256sum_str(std::string_view str, crypto::hash& hash);

View File

@ -1,5 +1,6 @@
#include "string_util.h"
#include <cassert>
#include <iomanip>
#include <sstream>
namespace tools {
@ -114,4 +115,31 @@ std::string friendly_duration(std::chrono::nanoseconds dur) {
return os.str();
}
std::string short_duration(std::chrono::duration<double> dur) {
std::ostringstream os;
os << std::fixed << std::setprecision(1);
if (dur >= 36h)
os << dur / 24h;
else if (dur >= 90min)
os << dur / 1h;
else if (dur >= 90s)
os << dur / 1min;
else if (dur >= 1s)
os << dur / 1s;
else if (dur >= 100ms)
os << std::setprecision(0) << dur / 1ms;
else if (dur >= 1ms)
os << dur / 1ms;
else if (dur >= 100us)
os << std::setprecision(0) << dur / 1us;
else if (dur >= 1us)
os << dur / 1us;
else if (dur >= 1ns)
os << std::setprecision(0) << dur / 1ns;
else
os << "0s";
return os.str();
}
}

View File

@ -170,9 +170,12 @@ T make_from_guts(std::string_view s) {
std::string lowercase_ascii_string(std::string_view src);
/// Converts a duration into a human friendlier string.
/// Converts a duration into a human friendlier string, such as "3d7d47m12s" or "347µs"
std::string friendly_duration(std::chrono::nanoseconds dur);
/// Converts a duration into a shorter, single-unit fractional display such as `42.3min`
std::string short_duration(std::chrono::duration<double> dur);
/// Given an array of string arguments, look for strings of the format <prefix><value> and return <value>
/// Returns empty string view if not found.
template <typename It>

View File

@ -34,17 +34,14 @@
#include <iomanip>
#include <thread>
#include <openssl/ssl.h>
#include <date/date.h>
#include "unbound.h"
#include "epee/string_tools.h"
#include "epee/wipeable_string.h"
#include "crypto/crypto.h"
#include "util.h"
#include "epee/readline_buffer.h"
#include "epee/misc_log_ex.h"
#include "string_util.h"
#include "i18n.h"
@ -60,21 +57,6 @@
namespace tools
{
static bool unbound_built_with_threads()
{
ub_ctx *ctx = ub_ctx_create();
if (!ctx) return false; // cheat a bit, should not happen unless OOM
char *oxen = strdup("oxen"), *unbound = strdup("unbound");
ub_ctx_zone_add(ctx, oxen, unbound); // this calls ub_ctx_finalize first, then errors out with UB_SYNTAX
free(unbound);
free(oxen);
// if no threads, bails out early with UB_NOERROR, otherwise fails with UB_AFTERFINAL id already finalized
bool with_threads = ub_ctx_async(ctx, 1) != 0; // UB_AFTERFINAL is not defined in public headers, check any error
ub_ctx_delete(ctx);
MINFO("libunbound was built " << (with_threads ? "with" : "without") << " threads");
return with_threads;
}
bool disable_core_dumps()
{
#ifdef __GLIBC__
@ -115,15 +97,6 @@ namespace tools
MCLOG_RED(el::Level::Warning, "global", "Running with glibc " << ver << ", hangs may occur - change glibc version if possible");
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(LIBRESSL_VERSION_TEXT)
SSL_library_init();
#else
OPENSSL_init_ssl(0, NULL);
#endif
if (!unbound_built_with_threads())
MCLOG_RED(el::Level::Warning, "global", "libunbound was not built with threads enabled - crashes may occur");
return true;
}
namespace

View File

@ -30,7 +30,7 @@
#pragma once
#include <boost/endian/conversion.hpp>
#include <oxenc/endian.h>
#include <optional>
#include <memory>
#include <string>
@ -85,7 +85,7 @@ namespace tools
// Copy an integer type, swapping to little-endian if needed
template <typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
void memcpy_one(char*& dest, T t) {
boost::endian::native_to_little_inplace(t);
oxenc::host_to_little_inplace(t);
std::memcpy(dest, &t, sizeof(T));
dest += sizeof(T);
}

View File

@ -291,7 +291,7 @@ namespace crypto {
ec_point Y;
};
void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
signature generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec) {
ge_p3 tmp3;
ec_scalar k;
s_comm buf;
@ -307,6 +307,7 @@ namespace crypto {
#endif
buf.h = prefix_hash;
buf.key = pub;
signature sig;
try_again:
random_scalar(k);
ge_scalarmult_base(&tmp3, &k);
@ -318,6 +319,11 @@ namespace crypto {
if (!sc_isnonzero((const unsigned char*)sig.r.data))
goto try_again;
memwipe(&k, sizeof(k));
return sig;
}
void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
sig = generate_signature(prefix_hash, pub, sec);
}
static constexpr ec_point infinity = {{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};

View File

@ -238,6 +238,7 @@ namespace crypto {
* Ed25519: given signature (R, s), (unhashed) message M, pubkey A:
* Check: sB == R + H(R||A||M)A
*/
signature generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec);
void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig);
// See above.
bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig);

View File

@ -39,13 +39,7 @@
#include <malloc.h>
#endif
// ANDROID, FreeBSD, OpenBSD and NetBSD also don't need timeb.h
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__ANDROID__) \
&& !defined(__NetBSD__)
#include <sys/timeb.h>
#else
#include <sys/time.h>
#endif
#include <sys/time.h>
#ifdef WIN32
#include <process.h>
@ -474,19 +468,6 @@ OAES_RET oaes_sprintf(
#ifdef OAES_HAVE_ISAAC
static void oaes_get_seed( char buf[RANDSIZ + 1] )
{
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
struct timeb timer;
struct tm *gmTimer;
char * _test = NULL;
ftime (&timer);
gmTimer = gmtime( &timer.time );
_test = (char *) calloc( sizeof( char ), timer.millitm );
sprintf( buf, "%04d%02d%02d%02d%02d%02d%03d%p%d",
gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday,
gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.millitm,
_test + timer.millitm, GETPID() );
#else
struct timeval timer;
struct tm *gmTimer;
char * _test = NULL;
@ -498,7 +479,6 @@ static void oaes_get_seed( char buf[RANDSIZ + 1] )
gmTimer->tm_year + 1900, gmTimer->tm_mon + 1, gmTimer->tm_mday,
gmTimer->tm_hour, gmTimer->tm_min, gmTimer->tm_sec, timer.tv_usec/1000,
_test + timer.tv_usec/1000, GETPID() );
#endif
if( _test )
free( _test );
@ -506,19 +486,6 @@ static void oaes_get_seed( char buf[RANDSIZ + 1] )
#else
static uint32_t oaes_get_seed(void)
{
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__ANDROID__) && !defined(__NetBSD__)
struct timeb timer;
struct tm *gmTimer;
char * _test = NULL;
uint32_t _ret = 0;
ftime (&timer);
gmTimer = gmtime( &timer.time );
_test = (char *) calloc( sizeof( char ), timer.millitm );
_ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday +
gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.millitm +
(uintptr_t) ( _test + timer.millitm ) + GETPID();
#else
struct timeval timer;
struct tm *gmTimer;
char * _test = NULL;
@ -530,7 +497,6 @@ static uint32_t oaes_get_seed(void)
_ret = gmTimer->tm_year + 1900 + gmTimer->tm_mon + 1 + gmTimer->tm_mday +
gmTimer->tm_hour + gmTimer->tm_min + gmTimer->tm_sec + timer.tv_usec/1000 +
(uintptr_t) ( _test + timer.tv_usec/1000 ) + GETPID();
#endif
if( _test )
free( _test );

View File

@ -68,7 +68,7 @@ DISABLE_VS_WARNINGS(4244 4345)
static_assert(sizeof(base_key) == sizeof(crypto::hash), "chacha key and hash should be the same size");
epee::mlocked<tools::scrubbed_arr<char, sizeof(base_key)+1>> data;
memcpy(data.data(), &base_key, sizeof(base_key));
data[sizeof(base_key)] = config::HASH_KEY_MEMORY;
data[sizeof(base_key)] = cryptonote::hashkey::MEMORY;
crypto::generate_chacha_key(data.data(), sizeof(data), key, 1);
}
//-----------------------------------------------------------------

View File

@ -1,39 +0,0 @@
// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <string>
#include "epee/span.h"
namespace cryptonote
{
typedef std::string blobdata;
}

View File

@ -1,4 +1,5 @@
#include "cryptonote_basic.h"
#include <oxenc/endian.h>
#include "cryptonote_format_utils.h"
@ -104,7 +105,10 @@ block::block(const block& b) :
block_header(b),
miner_tx{b.miner_tx},
tx_hashes{b.tx_hashes},
signatures{b.signatures}
signatures{b.signatures},
height{b.height},
service_node_winner_key{b.service_node_winner_key},
reward{b.reward}
{
copy_hash(b);
}
@ -113,7 +117,10 @@ block::block(block&& b) :
block_header(std::move(b)),
miner_tx{std::move(b.miner_tx)},
tx_hashes{std::move(b.tx_hashes)},
signatures{std::move(b.signatures)}
signatures{std::move(b.signatures)},
height{std::move(b.height)},
service_node_winner_key{std::move(b.service_node_winner_key)},
reward{std::move(b.reward)}
{
copy_hash(b);
}
@ -124,6 +131,9 @@ block& block::operator=(const block& b)
miner_tx = b.miner_tx;
tx_hashes = b.tx_hashes;
signatures = b.signatures;
height = b.height;
service_node_winner_key = b.service_node_winner_key;
reward = b.reward;
copy_hash(b);
return *this;
}
@ -133,6 +143,9 @@ block& block::operator=(block&& b)
miner_tx = std::move(b.miner_tx);
tx_hashes = std::move(b.tx_hashes);
signatures = std::move(b.signatures);
height = std::move(b.height);
service_node_winner_key = std::move(b.service_node_winner_key);
reward = std::move(b.reward);
copy_hash(b);
return *this;
}
@ -146,4 +159,23 @@ void block::set_hash_valid(bool v) const
hash_valid.store(v,std::memory_order_release);
}
// Convert the address to an integer and then performs (address % interval)
// it does this by taking the first 64 bits of the public_view_key and converting to an integer
// This is used to determine when an address gets paid their batching reward.
uint64_t account_public_address::modulus(uint64_t interval) const
{
uint64_t address_as_integer = 0;
std::memcpy(&address_as_integer, m_view_public_key.data, sizeof(address_as_integer));
oxenc::host_to_little_inplace(address_as_integer);
return address_as_integer % interval;
}
uint64_t account_public_address::next_payout_height(uint64_t current_height, uint64_t interval) const
{
uint64_t next_payout_height = current_height + (modulus(interval) - current_height % interval);
if (next_payout_height <= current_height)
next_payout_height += interval;
return next_payout_height;
}
}

View File

@ -176,9 +176,9 @@ namespace cryptonote
static char const* version_to_string(txversion v);
static char const* type_to_string(txtype type);
static constexpr txversion get_min_version_for_hf(uint8_t hf_version);
static txversion get_max_version_for_hf(uint8_t hf_version);
static constexpr txtype get_max_type_for_hf (uint8_t hf_version);
static constexpr txversion get_min_version_for_hf(hf hf_version);
static txversion get_max_version_for_hf(hf hf_version);
static constexpr txtype get_max_type_for_hf (hf hf_version);
// tx information
txversion version;
@ -208,7 +208,9 @@ namespace cryptonote
FIELD(vin)
FIELD(vout)
if (version >= txversion::v3_per_output_unlock_times && vout.size() != output_unlock_times.size())
{
throw std::invalid_argument{"v3 tx without correct unlock times"};
}
FIELD(extra)
if (version >= txversion::v4_tx_types)
ENUM_FIELD_N("type", type, type < txtype::_count);
@ -393,22 +395,12 @@ namespace cryptonote
struct block_header
{
uint8_t major_version = cryptonote::network_version_7;
uint8_t minor_version = cryptonote::network_version_7; // now used as a voting mechanism, rather than how this particular block is built
hf major_version = hf::hf7;
uint8_t minor_version = 0;
uint64_t timestamp;
crypto::hash prev_id;
uint32_t nonce;
pulse_header pulse = {};
BEGIN_SERIALIZE()
VARINT_FIELD(major_version)
VARINT_FIELD(minor_version)
VARINT_FIELD(timestamp)
FIELD(prev_id)
FIELD(nonce)
if (major_version >= cryptonote::network_version_16_pulse)
FIELD(pulse)
END_SERIALIZE()
};
struct block: public block_header
@ -429,26 +421,49 @@ namespace cryptonote
void set_hash_valid(bool v) const;
transaction miner_tx;
size_t height;
crypto::public_key service_node_winner_key;
uint64_t reward = 0;
std::vector<crypto::hash> tx_hashes;
// hash cache
mutable crypto::hash hash;
std::vector<service_nodes::quorum_signature> signatures;
BEGIN_SERIALIZE_OBJECT()
if (Archive::is_deserializer)
set_hash_valid(false);
FIELDS(static_cast<block_header&>(*this))
FIELD(miner_tx)
FIELD(tx_hashes)
if (tx_hashes.size() > CRYPTONOTE_MAX_TX_PER_BLOCK)
throw std::invalid_argument{"too many txs in block"};
if (major_version >= cryptonote::network_version_16_pulse)
FIELD(signatures)
END_SERIALIZE()
};
template <class Archive>
void serialize_value(Archive& ar, block_header& b) {
using namespace serialization;
field(ar, "major_version", b.major_version);
field_varint(ar, "minor_version", b.minor_version);
field_varint(ar, "timestamp", b.timestamp);
field(ar, "prev_id", b.prev_id);
field(ar, "nonce", b.nonce);
if (b.major_version >= hf::hf16_pulse)
field(ar, "pulse", b.pulse);
}
template <class Archive>
void serialize_value(Archive& ar, block& b) {
auto _obj = ar.begin_object();
if constexpr (Archive::is_deserializer)
b.set_hash_valid(false);
serialization::value(ar, static_cast<block_header&>(b));
field(ar, "miner_tx", b.miner_tx);
field(ar, "tx_hashes", b.tx_hashes);
if (b.tx_hashes.size() > MAX_TX_PER_BLOCK)
throw std::invalid_argument{"too many txs in block"};
if (b.major_version >= hf::hf16_pulse)
field(ar, "signatures", b.signatures);
if (b.major_version >= hf::hf19_reward_batching)
{
field_varint(ar, "height", b.height);
field(ar, "service_node_winner_key", b.service_node_winner_key);
field(ar, "reward", b.reward);
}
}
/************************************************************************/
/* */
@ -478,6 +493,10 @@ namespace cryptonote
{
return !(*this == rhs);
}
uint64_t modulus(uint64_t interval) const;
uint64_t next_payout_height(uint64_t current_height, uint64_t interval) const;
};
inline constexpr account_public_address null_address{};
@ -503,9 +522,9 @@ namespace cryptonote
using byte_and_output_fees = std::pair<uint64_t, uint64_t>;
//---------------------------------------------------------------
constexpr txversion transaction_prefix::get_min_version_for_hf(uint8_t hf_version)
constexpr txversion transaction_prefix::get_min_version_for_hf(hf hf_version)
{
if (hf_version >= cryptonote::network_version_7 && hf_version <= cryptonote::network_version_10_bulletproofs)
if (hf_version >= hf::hf7 && hf_version <= hf::hf10_bulletproofs)
return txversion::v2_ringct;
return txversion::v4_tx_types;
}
@ -514,26 +533,26 @@ namespace cryptonote
// tests can still use particular hard forks without needing to actually generate pre-v4 txes.
namespace hack { inline bool test_suite_permissive_txes = false; }
inline txversion transaction_prefix::get_max_version_for_hf(uint8_t hf_version)
inline txversion transaction_prefix::get_max_version_for_hf(hf hf_version)
{
if (!hack::test_suite_permissive_txes) {
if (hf_version >= cryptonote::network_version_7 && hf_version <= cryptonote::network_version_8)
if (hf_version >= hf::hf7 && hf_version <= hf::hf8)
return txversion::v2_ringct;
if (hf_version >= cryptonote::network_version_9_service_nodes && hf_version <= cryptonote::network_version_10_bulletproofs)
if (hf_version >= hf::hf9_service_nodes && hf_version <= hf::hf10_bulletproofs)
return txversion::v3_per_output_unlock_times;
}
return txversion::v4_tx_types;
}
constexpr txtype transaction_prefix::get_max_type_for_hf(uint8_t hf_version)
constexpr txtype transaction_prefix::get_max_type_for_hf(hf hf_version)
{
txtype result = txtype::standard;
if (hf_version >= network_version_15_ons) result = txtype::oxen_name_system;
else if (hf_version >= network_version_14_blink) result = txtype::stake;
else if (hf_version >= network_version_11_infinite_staking) result = txtype::key_image_unlock;
else if (hf_version >= network_version_9_service_nodes) result = txtype::state_change;
if (hf_version >= hf::hf15_ons) result = txtype::oxen_name_system;
else if (hf_version >= hf::hf14_blink) result = txtype::stake;
else if (hf_version >= hf::hf11_infinite_staking) result = txtype::key_image_unlock;
else if (hf_version >= hf::hf9_service_nodes) result = txtype::state_change;
return result;
}
@ -563,12 +582,25 @@ namespace cryptonote
}
}
inline std::ostream &operator<<(std::ostream &os, txtype t) {
inline std::ostream& operator<<(std::ostream& os, txtype t) {
return os << transaction::type_to_string(t);
}
inline std::ostream &operator<<(std::ostream &os, txversion v) {
inline std::ostream& operator<<(std::ostream& os, txversion v) {
return os << transaction::version_to_string(v);
}
inline std::ostream& operator<<(std::ostream& os, hf v) = delete;/*{
return os << "HF" << static_cast<int>(v);
}*/
// Serialization for the `hf` type; this is simply writing/reading the underlying uint8_t value
template <class Archive>
void serialize_value(Archive& ar, hf& x) {
auto val = static_cast<std::underlying_type_t<hf>>(x);
serialization::value(ar, val);
if constexpr (Archive::is_deserializer)
x = static_cast<hf>(val);
}
}
namespace std {

View File

@ -35,11 +35,9 @@
#include "serialization/container.h"
#include "cryptonote_format_utils.h"
#include "cryptonote_config.h"
#include "epee/misc_language.h"
#include "common/base58.h"
#include "crypto/hash.h"
#include "epee/int-util.h"
#include "common/dns_utils.h"
#include "common/oxen.h"
#include <cfenv>
@ -67,38 +65,33 @@ namespace cryptonote {
constexpr cryptonote::pulse_random_value empty_random_value = {};
bool bitset = blk_header.pulse.validator_bitset > 0;
bool random_value = !(blk_header.pulse.random_value == empty_random_value);
uint8_t hf_version = blk_header.major_version;
bool result = hf_version >= cryptonote::network_version_16_pulse && (bitset || random_value);
auto hf_version = blk_header.major_version;
bool result = hf_version >= hf::hf16_pulse && (bitset || random_value);
return result;
}
//-----------------------------------------------------------------------------------------------
bool block_has_pulse_components(block const &blk)
{
bool signatures = blk.signatures.size();
uint8_t hf_version = blk.major_version;
bool signatures = blk.signatures.size();
auto hf_version = blk.major_version;
bool result =
(hf_version >= cryptonote::network_version_16_pulse && signatures) || block_header_has_pulse_components(blk);
(hf_version >= hf::hf16_pulse && signatures) || block_header_has_pulse_components(blk);
return result;
}
//-----------------------------------------------------------------------------------------------
size_t get_min_block_weight(uint8_t version)
size_t get_min_block_weight(hf version)
{
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
}
//-----------------------------------------------------------------------------------------------
size_t get_max_tx_size()
{
return CRYPTONOTE_MAX_TX_SIZE;
return BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
}
//-----------------------------------------------------------------------------------------------
// TODO(oxen): Move into oxen_economy, this will require access to oxen::exp2
uint64_t block_reward_unpenalized_formula_v7(uint64_t already_generated_coins, uint64_t height)
{
uint64_t emission_supply_component = (already_generated_coins * EMISSION_SUPPLY_MULTIPLIER) / EMISSION_SUPPLY_DIVISOR;
uint64_t result = (EMISSION_LINEAR_BASE - emission_supply_component) / EMISSION_DIVISOR;
uint64_t emission_supply_component = (already_generated_coins * oxen::EMISSION_SUPPLY_MULTIPLIER) / oxen::EMISSION_SUPPLY_DIVISOR;
uint64_t result = (oxen::EMISSION_LINEAR_BASE - emission_supply_component) / oxen::EMISSION_DIVISOR;
// Check if we just overflowed
if (emission_supply_component > EMISSION_LINEAR_BASE)
if (emission_supply_component > oxen::EMISSION_LINEAR_BASE)
result = 0;
return result;
}
@ -110,21 +103,21 @@ namespace cryptonote {
return result;
}
bool get_base_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint64_t &reward_unpenalized, uint8_t version, uint64_t height) {
bool get_base_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint64_t &reward_unpenalized, hf version, uint64_t height) {
//premine reward
if (already_generated_coins == 0)
{
reward = 22'500'000 * COIN;
reward = 22'500'000 * oxen::COIN;
return true;
}
static_assert((TARGET_BLOCK_TIME % 1min) == 0s, "difficulty targets must be a multiple of a minute");
uint64_t base_reward =
version >= network_version_17 ? BLOCK_REWARD_HF17 :
version >= network_version_15_ons ? BLOCK_REWARD_HF15 :
version >= network_version_8 ? block_reward_unpenalized_formula_v8(height) :
version >= hf::hf17 ? oxen::BLOCK_REWARD_HF17 :
version >= hf::hf15_ons ? oxen::BLOCK_REWARD_HF15 :
version >= hf::hf8 ? block_reward_unpenalized_formula_v8(height) :
block_reward_unpenalized_formula_v7(already_generated_coins, height);
uint64_t full_reward_zone = get_min_block_weight(version);
@ -166,6 +159,17 @@ namespace cryptonote {
return true;
}
//------------------------------------------------------------------------------------
batch_sn_payment::batch_sn_payment(std::string addr, uint64_t amt, cryptonote::network_type nettype):address(addr),amount(amt){
cryptonote::get_account_address_from_str(address_info, nettype, address);
};
batch_sn_payment::batch_sn_payment(cryptonote::address_parse_info& addr_info, uint64_t amt, cryptonote::network_type nettype):address_info(addr_info),amount(amt){
address = cryptonote::get_account_address_as_str(nettype, address_info.is_subaddress, address_info.address);
};
batch_sn_payment::batch_sn_payment(const cryptonote::account_public_address& addr, uint64_t amt, cryptonote::network_type nettype):amount(amt){
address_info = cryptonote::address_parse_info{addr,0};
address = cryptonote::get_account_address_as_str(nettype, address_info.is_subaddress, address_info.address);
};
//------------------------------------------------------------------------------------
uint8_t get_account_address_checksum(const public_address_outer_blob& bl)
{
const unsigned char* pbuf = reinterpret_cast<const unsigned char*>(&bl);
@ -192,7 +196,8 @@ namespace cryptonote {
, account_public_address const & adr
)
{
uint64_t address_prefix = subaddress ? get_config(nettype).CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : get_config(nettype).CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
auto& conf = get_config(nettype);
uint64_t address_prefix = subaddress ? conf.PUBLIC_SUBADDRESS_BASE58_PREFIX : conf.PUBLIC_ADDRESS_BASE58_PREFIX;
return tools::base58::encode_addr(address_prefix, t_serializable_object_to_blob(adr));
}
@ -203,7 +208,7 @@ namespace cryptonote {
, crypto::hash8 const & payment_id
)
{
uint64_t integrated_address_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
uint64_t integrated_address_prefix = get_config(nettype).PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
integrated_address iadr = {
adr, payment_id
@ -222,11 +227,12 @@ namespace cryptonote {
, const std::string_view str
)
{
uint64_t address_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
uint64_t integrated_address_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
uint64_t subaddress_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX;
auto& conf = get_config(nettype);
uint64_t address_prefix = conf.PUBLIC_ADDRESS_BASE58_PREFIX;
uint64_t integrated_address_prefix = conf.PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
uint64_t subaddress_prefix = conf.PUBLIC_SUBADDRESS_BASE58_PREFIX;
blobdata data;
std::string data;
uint64_t prefix{0};
if (!tools::base58::decode_addr(str, prefix, data))
{
@ -282,21 +288,6 @@ namespace cryptonote {
return true;
}
//--------------------------------------------------------------------------------
bool get_account_address_from_str_or_url(
address_parse_info& info
, network_type nettype
, const std::string_view str_or_url
, std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm
)
{
if (get_account_address_from_str(info, nettype, str_or_url))
return true;
bool dnssec_valid;
std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid, dns_confirm);
return !address_str.empty() &&
get_account_address_from_str(info, nettype, address_str);
}
//--------------------------------------------------------------------------------
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) {
return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b);
}

View File

@ -54,10 +54,32 @@ namespace cryptonote {
virtual void init() = 0;
};
struct address_parse_info
{
account_public_address address;
bool is_subaddress;
bool has_payment_id;
crypto::hash8 payment_id;
std::string as_str(network_type nettype) const;
KV_MAP_SERIALIZABLE
};
struct batch_sn_payment {
std::string address;
cryptonote::address_parse_info address_info;
uint64_t amount;
batch_sn_payment() = default;
batch_sn_payment(std::string addr, uint64_t amt, cryptonote::network_type nettype);
batch_sn_payment(cryptonote::address_parse_info& addr_info, uint64_t amt, cryptonote::network_type nettype);
batch_sn_payment(const cryptonote::account_public_address& addr, uint64_t amt, cryptonote::network_type nettype);
};
class ValidateMinerTxHook
{
public:
virtual bool validate_miner_tx(cryptonote::block const &block, struct block_reward_parts const &reward_parts) const = 0;
virtual bool validate_miner_tx(cryptonote::block const &block, struct block_reward_parts const &reward_parts, std::optional<std::vector<cryptonote::batch_sn_payment>> const &batched_sn_payments) const = 0;
};
class AltBlockAddedHook
@ -89,28 +111,17 @@ namespace cryptonote {
return addresses[0];
}
struct address_parse_info
{
account_public_address address;
bool is_subaddress;
bool has_payment_id;
crypto::hash8 payment_id;
std::string as_str(network_type nettype) const;
KV_MAP_SERIALIZABLE
};
/************************************************************************/
/* Cryptonote helper functions */
/************************************************************************/
bool block_header_has_pulse_components(block_header const &blk_header);
bool block_has_pulse_components(block const &blk);
size_t get_min_block_weight(uint8_t version);
size_t get_max_tx_size();
size_t get_min_block_weight(hf version);
uint64_t block_reward_unpenalized_formula_v7(uint64_t already_generated_coins, uint64_t height);
uint64_t block_reward_unpenalized_formula_v8(uint64_t height);
bool get_base_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint64_t &reward_unpenalized, uint8_t version, uint64_t height);
bool get_base_block_reward(size_t median_weight, size_t current_block_weight, uint64_t already_generated_coins, uint64_t &reward, uint64_t &reward_unpenalized, hf version, uint64_t height);
uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl);
@ -140,13 +151,6 @@ namespace cryptonote {
, const std::string_view str
);
bool get_account_address_from_str_or_url(
address_parse_info& info
, network_type nettype
, const std::string_view str_or_url
, std::function<std::string(const std::string_view, const std::vector<std::string>&, bool)> dns_confirm = return_first_address
);
bool is_coinbase(const transaction& tx);
bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b);

View File

@ -215,6 +215,11 @@ namespace boost
//------------------
a & b.miner_tx;
a & b.tx_hashes;
if (ver < 19)
return;
a & b.height;
a & b.service_node_winner_key;
a & b.reward;
}
template <class Archive>

View File

@ -32,9 +32,10 @@
#include <atomic>
#include <boost/algorithm/string.hpp>
#include <limits>
#include <oxenmq/hex.h>
#include <oxenc/hex.h>
#include <variant>
#include "common/hex.h"
#include "cryptonote_core/service_node_list.h"
#include "epee/wipeable_string.h"
#include "epee/string_tools.h"
#include "common/i18n.h"
@ -91,7 +92,7 @@ namespace cryptonote
++nlr;
nlr += 6;
const size_t bp_size = 32 * (9 + 2 * nlr);
CHECK_AND_ASSERT_THROW_MES_L1(n_outputs <= BULLETPROOF_MAX_OUTPUTS, "maximum number of outputs is " + std::to_string(BULLETPROOF_MAX_OUTPUTS) + " per transaction");
CHECK_AND_ASSERT_THROW_MES_L1(n_outputs <= TX_BULLETPROOF_MAX_OUTPUTS, "maximum number of outputs is " + std::to_string(TX_BULLETPROOF_MAX_OUTPUTS) + " per transaction");
CHECK_AND_ASSERT_THROW_MES_L1(bp_base * n_padded_outputs >= bp_size, "Invalid bulletproof clawback: bp_base " + std::to_string(bp_base) + ", n_padded_outputs "
+ std::to_string(n_padded_outputs) + ", bp_size " + std::to_string(bp_size));
const uint64_t bp_clawback = (bp_base * n_padded_outputs - bp_size) * 4 / 5;
@ -353,80 +354,65 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
uint64_t power_integral(uint64_t a, uint64_t b)
{
if(b == 0)
return 1;
uint64_t total = a;
for(uint64_t i = 1; i != b; i++)
total *= a;
return total;
}
//---------------------------------------------------------------
bool parse_amount(uint64_t& amount, std::string_view str_amount)
std::optional<uint64_t> parse_amount(std::string_view str_amount)
{
uint64_t amount;
tools::trim(str_amount);
auto parts = tools::split(str_amount, "."sv);
if (parts.size() > 2)
return false; // 123.456.789 no thanks.
return std::nullopt; // 123.456.789 no thanks.
if (parts.size() == 2 && parts[1].empty())
parts.pop_back(); // allow "123." (treat it as as "123")
if (parts[0].find_first_not_of("0123456789"sv) != std::string::npos)
return false; // whole part contains non-digit
return std::nullopt; // whole part contains non-digit
if (parts[0].empty()) {
// Only allow an empty whole number part if there is a fractional part.
if (parts.size() == 1)
return false;
return std::nullopt;
amount = 0;
}
else
{
if (!tools::parse_int(parts[0], amount))
return false;
return std::nullopt;
// Scale up the number (e.g. 12 from "12.45") to atomic units.
//
// TODO: get rid of the user-configurable default_decimal_point nonsense and just multiply
// this value by the `COIN` constant.
for (size_t i = 0; i < CRYPTONOTE_DISPLAY_DECIMAL_POINT; i++)
{
if (amount > std::numeric_limits<uint64_t>::max() / 10)
return false; // would overflow
amount *= 10;
}
if (amount > std::numeric_limits<uint64_t>::max() / oxen::COIN)
return std::nullopt; // would overflow
amount *= oxen::COIN;
}
if (parts.size() == 1)
return true;
return amount;
if (parts[1].find_first_not_of("0123456789"sv) != std::string::npos)
return false; // fractional part contains non-digit
return std::nullopt; // fractional part contains non-digit
// If too long, but with insignificant 0's, trim them off
while (parts[1].size() > CRYPTONOTE_DISPLAY_DECIMAL_POINT && parts[1].back() == '0')
while (parts[1].size() > oxen::DISPLAY_DECIMAL_POINT && parts[1].back() == '0')
parts[1].remove_suffix(1);
if (parts[1].size() > CRYPTONOTE_DISPLAY_DECIMAL_POINT)
return false; // fractional part has too many significant digits
if (parts[1].size() > oxen::DISPLAY_DECIMAL_POINT)
return std::nullopt; // fractional part has too many significant digits
uint64_t fractional;
if (!tools::parse_int(parts[1], fractional))
return false;
return std::nullopt;
// Scale up the value if it wasn't a full fractional value, e.g. if we have "10.45" then we
// need to convert the 45 we just parsed to 450'000'000.
for (size_t i = parts[1].size(); i < CRYPTONOTE_DISPLAY_DECIMAL_POINT; i++)
for (size_t i = parts[1].size(); i < oxen::DISPLAY_DECIMAL_POINT; i++)
fractional *= 10;
if (fractional > std::numeric_limits<uint64_t>::max() - amount)
return false; // would overflow
return std::nullopt; // would overflow
amount += fractional;
return true;
return amount;
}
//---------------------------------------------------------------
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size)
@ -541,7 +527,7 @@ namespace cryptonote
try {
serialization::deserialize_all(ar, tx_extra_fields);
} catch (const std::exception& e) {
MWARNING(__func__ << ": failed to deserialize extra field: " << e.what() << "; extra = " << oxenmq::to_hex(tx_extra.begin(), tx_extra.end()));
MWARNING(__func__ << ": failed to deserialize extra field: " << e.what() << "; extra = " << oxenc::to_hex(tx_extra.begin(), tx_extra.end()));
return false;
}
@ -627,7 +613,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce)
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const std::string& extra_nonce)
{
CHECK_AND_ASSERT_MES(extra_nonce.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max");
tx_extra.reserve(tx_extra.size() + 2 + extra_nonce.size());
@ -637,10 +623,10 @@ namespace cryptonote
return true;
}
bool add_service_node_state_change_to_tx_extra(std::vector<uint8_t>& tx_extra, const tx_extra_service_node_state_change& state_change, const uint8_t hf_version)
bool add_service_node_state_change_to_tx_extra(std::vector<uint8_t>& tx_extra, const tx_extra_service_node_state_change& state_change, const hf hf_version)
{
tx_extra_field field;
if (hf_version < network_version_12_checkpointing)
if (hf_version < hf::hf12_checkpointing)
{
CHECK_AND_ASSERT_MES(state_change.state == service_nodes::new_state::deregister, false, "internal error: cannot construct an old deregistration for a non-deregistration state change (before hardfork v12)");
field = tx_extra_service_node_deregister_old{state_change};
@ -715,36 +701,22 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool add_service_node_register_to_tx_extra(
std::vector<uint8_t>& tx_extra,
const std::vector<cryptonote::account_public_address>& addresses,
uint64_t portions_for_operator,
const std::vector<uint64_t>& portions,
uint64_t expiration_timestamp,
const crypto::signature& service_node_signature)
bool add_service_node_registration_to_tx_extra(std::vector<uint8_t>& tx_extra, const service_nodes::registration_details& reg)
{
if (addresses.size() != portions.size())
tx_extra_field field;
auto& txreg = field.emplace<tx_extra_service_node_register>();
txreg.amounts.reserve(reg.reserved.size());
txreg.public_spend_keys.reserve(reg.reserved.size());
txreg.public_view_keys.reserve(reg.reserved.size());
for (const auto& [addr, amount] : reg.reserved)
{
LOG_ERROR("Tried to serialize registration with more addresses than portions, this should never happen");
return false;
txreg.public_spend_keys.push_back(addr.m_spend_public_key);
txreg.public_view_keys.push_back(addr.m_view_public_key);
txreg.amounts.push_back(amount);
}
std::vector<crypto::public_key> public_view_keys(addresses.size());
std::vector<crypto::public_key> public_spend_keys(addresses.size());
for (size_t i = 0; i < addresses.size(); i++)
{
public_view_keys[i] = addresses[i].m_view_public_key;
public_spend_keys[i] = addresses[i].m_spend_public_key;
}
// convert to variant
tx_extra_field field =
tx_extra_service_node_register{
public_spend_keys,
public_view_keys,
portions_for_operator,
portions,
expiration_timestamp,
service_node_signature
};
txreg.fee = reg.fee;
txreg.hf_or_expiration = reg.hf;
txreg.signature = reg.signature;
bool r = add_tx_extra_field_to_tx_extra(tx_extra, field);
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra registration tx");
@ -756,9 +728,9 @@ namespace cryptonote
add_tx_extra<tx_extra_service_node_winner>(tx_extra, winner);
}
//---------------------------------------------------------------
bool get_service_node_state_change_from_tx_extra(const std::vector<uint8_t>& tx_extra, tx_extra_service_node_state_change &state_change, const uint8_t hf_version)
bool get_service_node_state_change_from_tx_extra(const std::vector<uint8_t>& tx_extra, tx_extra_service_node_state_change &state_change, const hf hf_version)
{
if (hf_version >= cryptonote::network_version_12_checkpointing) {
if (hf_version >= hf::hf12_checkpointing) {
// Look for a new-style state change field:
return get_field_from_tx_extra(tx_extra, state_change);
}
@ -807,7 +779,7 @@ namespace cryptonote
value(newar, field);
} while (ar.remaining_bytes() > 0);
} catch (const std::exception& e) {
LOG_PRINT_L1(__func__ << ": failed to deserialize extra field: " << e.what() << "; extra = " << oxenmq::to_hex(tx_extra.begin(), tx_extra.end()));
LOG_PRINT_L1(__func__ << ": failed to deserialize extra field: " << e.what() << "; extra = " << oxenc::to_hex(tx_extra.begin(), tx_extra.end()));
return false;
}
@ -818,7 +790,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id)
void set_payment_id_to_tx_extra_nonce(std::string& extra_nonce, const crypto::hash& payment_id)
{
extra_nonce.clear();
extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID);
@ -826,7 +798,7 @@ namespace cryptonote
std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
}
//---------------------------------------------------------------
void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id)
void set_encrypted_payment_id_to_tx_extra_nonce(std::string& extra_nonce, const crypto::hash8& payment_id)
{
extra_nonce.clear();
extra_nonce.push_back(TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID);
@ -834,7 +806,7 @@ namespace cryptonote
std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
}
//---------------------------------------------------------------
bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id)
bool get_payment_id_from_tx_extra_nonce(const std::string& extra_nonce, crypto::hash& payment_id)
{
if(sizeof(crypto::hash) + 1 != extra_nonce.size())
return false;
@ -844,7 +816,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id)
bool get_encrypted_payment_id_from_tx_extra_nonce(const std::string& extra_nonce, crypto::hash8& payment_id)
{
if(sizeof(crypto::hash8) + 1 != extra_nonce.size())
return false;
@ -883,9 +855,19 @@ namespace cryptonote
//---------------------------------------------------------------
uint64_t get_block_height(const block& b)
{
CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1 (size is: " << b.miner_tx.vin.size() << ")");
CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], txin_gen, coinbase_in, 0);
return coinbase_in.height;
cryptonote::block bl = b;
if (b.miner_tx.vout.size() > 0)
{
CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1 (size is: " << b.miner_tx.vin.size() << ")");
CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], txin_gen, coinbase_in, 0);
if (b.major_version >= hf::hf19_reward_batching)
{
CHECK_AND_ASSERT_MES(coinbase_in.height == b.height, 0, "wrong miner tx in block: " << get_block_hash(b));
}
return coinbase_in.height;
} else {
return b.height;
}
}
//---------------------------------------------------------------
bool check_inputs_types_supported(const transaction& tx)
@ -895,7 +877,6 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(std::holds_alternative<txin_to_key>(in), false, "wrong variant type: "
<< tools::type_name(tools::variant_type(in)) << ", expected " << tools::type_name<txin_to_key>()
<< ", in transaction id=" << get_transaction_hash(tx));
}
return true;
}
@ -969,7 +950,7 @@ namespace cryptonote
//---------------------------------------------------------------
std::string short_hash_str(const crypto::hash& h)
{
return oxenmq::to_hex(tools::view_guts(h).substr(0, 4)) + "....";
return oxenc::to_hex(tools::view_guts(h).substr(0, 4)) + "....";
}
//---------------------------------------------------------------
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_pub_keys, size_t output_index)
@ -1047,13 +1028,17 @@ namespace cryptonote
cn_fast_hash(blob.data(), blob.size(), res);
}
//---------------------------------------------------------------
std::string print_money(uint64_t amount, bool trim_insignificant)
std::string print_money(uint64_t amount, bool strip_zeros)
{
std::string s = tools::int_to_string(amount);
if (s.size() <= CRYPTONOTE_DISPLAY_DECIMAL_POINT)
s.insert(0, CRYPTONOTE_DISPLAY_DECIMAL_POINT - s.size() + 1, '0');
s.insert(s.size() - CRYPTONOTE_DISPLAY_DECIMAL_POINT, ".");
if (trim_insignificant) {
constexpr unsigned int decimal_point = oxen::DISPLAY_DECIMAL_POINT;
std::string s = std::to_string(amount);
if(s.size() < decimal_point+1)
{
s.insert(0, decimal_point+1 - s.size(), '0');
}
s.insert(s.size() - decimal_point, ".");
if (strip_zeros)
{
while (s.back() == '0')
s.pop_back();
if (s.back() == '.')
@ -1062,6 +1047,14 @@ namespace cryptonote
return s;
}
//---------------------------------------------------------------
std::string format_money(uint64_t amount, bool strip_zeros)
{
auto value = print_money(amount, strip_zeros);
value += ' ';
value += get_unit();
return value;
}
//---------------------------------------------------------------
std::string print_tx_verification_context(tx_verification_context const &tvc, transaction const *tx)
{
std::ostringstream os;
@ -1189,7 +1182,7 @@ namespace cryptonote
return get_transaction_hash(t, res, NULL);
}
//---------------------------------------------------------------
[[nodiscard]] bool calculate_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob, crypto::hash& res)
[[nodiscard]] bool calculate_transaction_prunable_hash(const transaction& t, const std::string *blob, crypto::hash& res)
{
if (t.version == txversion::v1)
return false;
@ -1217,7 +1210,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
crypto::hash get_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blobdata)
crypto::hash get_transaction_prunable_hash(const transaction& t, const std::string* blobdata)
{
crypto::hash res;
CHECK_AND_ASSERT_THROW_MES(calculate_transaction_prunable_hash(t, blobdata, res), "Failed to calculate tx prunable hash");
@ -1273,7 +1266,7 @@ namespace cryptonote
// prefix
get_transaction_prefix_hash(t, hashes[0]);
const blobdata blob = tx_to_blob(t);
const std::string blob = tx_to_blob(t);
CHECK_AND_ASSERT_MES(!blob.empty(), false, "Failed to convert tx to blob");
// TODO(oxen): Not sure if this is the right fix, we may just want to set
@ -1330,38 +1323,6 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool get_registration_hash(const std::vector<cryptonote::account_public_address>& addresses, uint64_t operator_portions, const std::vector<uint64_t>& portions, uint64_t expiration_timestamp, crypto::hash& hash)
{
if (addresses.size() != portions.size())
{
LOG_ERROR("get_registration_hash addresses.size() != portions.size()");
return false;
}
uint64_t portions_left = STAKING_PORTIONS;
for (uint64_t portion : portions)
{
if (portion > portions_left)
{
LOG_ERROR(tr("Your registration has more than ") << STAKING_PORTIONS << tr(" portions, this registration is invalid!"));
return false;
}
portions_left -= portion;
}
size_t size = sizeof(uint64_t) + addresses.size() * (sizeof(cryptonote::account_public_address) + sizeof(uint64_t)) + sizeof(uint64_t);
std::string buffer;
buffer.reserve(size);
buffer += tools::view_guts(operator_portions);
for (size_t i = 0; i < addresses.size(); i++)
{
buffer += tools::view_guts(addresses[i]);
buffer += tools::view_guts(portions[i]);
}
buffer += tools::view_guts(expiration_timestamp);
assert(buffer.size() == size);
crypto::cn_fast_hash(buffer.data(), buffer.size(), hash);
return true;
}
//---------------------------------------------------------------
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
{
if (t.is_hash_valid())
@ -1396,9 +1357,9 @@ namespace cryptonote
return get_transaction_hash(t, res, &blob_size);
}
//---------------------------------------------------------------
blobdata get_block_hashing_blob(const block& b)
std::string get_block_hashing_blob(const block& b)
{
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
std::string blob = t_serializable_object_to_blob(static_cast<block_header>(b));
crypto::hash tree_root_hash = get_tx_tree_hash(b);
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
@ -1485,22 +1446,22 @@ namespace cryptonote
return parse_and_validate_block_from_blob(b_blob, b, &block_hash);
}
//---------------------------------------------------------------
blobdata block_to_blob(const block& b)
std::string block_to_blob(const block& b)
{
return t_serializable_object_to_blob(b);
}
//---------------------------------------------------------------
bool block_to_blob(const block& b, blobdata& b_blob)
bool block_to_blob(const block& b, std::string& b_blob)
{
return t_serializable_object_to_blob(b, b_blob);
}
//---------------------------------------------------------------
blobdata tx_to_blob(const transaction& tx)
std::string tx_to_blob(const transaction& tx)
{
return t_serializable_object_to_blob(tx);
}
//---------------------------------------------------------------
bool tx_to_blob(const transaction& tx, blobdata& b_blob)
bool tx_to_blob(const transaction& tx, std::string& b_blob)
{
return t_serializable_object_to_blob(tx, b_blob);
}

View File

@ -29,7 +29,6 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include "blobdatatype.h"
#include "cryptonote_basic_impl.h"
#include "tx_extra.h"
#include "account.h"
@ -46,7 +45,10 @@ namespace epee
class wipeable_string;
}
namespace service_nodes { struct quorum_vote_t; }
namespace service_nodes {
struct quorum_vote_t;
struct registration_details;
}
namespace cryptonote
{
@ -129,12 +131,12 @@ namespace cryptonote
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index = 0);
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx, size_t pk_index = 0);
bool add_service_node_state_change_to_tx_extra(std::vector<uint8_t>& tx_extra, const tx_extra_service_node_state_change& state_change, uint8_t hf_version);
bool get_service_node_state_change_from_tx_extra(const std::vector<uint8_t>& tx_extra, tx_extra_service_node_state_change& state_change, uint8_t hf_version);
bool add_service_node_state_change_to_tx_extra(std::vector<uint8_t>& tx_extra, const tx_extra_service_node_state_change& state_change, hf hf_version);
bool get_service_node_state_change_from_tx_extra(const std::vector<uint8_t>& tx_extra, tx_extra_service_node_state_change& state_change, hf hf_version);
bool get_service_node_pubkey_from_tx_extra(const std::vector<uint8_t>& tx_extra, crypto::public_key& pubkey);
bool get_service_node_contributor_from_tx_extra(const std::vector<uint8_t>& tx_extra, cryptonote::account_public_address& address);
bool add_service_node_register_to_tx_extra(std::vector<uint8_t>& tx_extra, const std::vector<cryptonote::account_public_address>& addresses, uint64_t portions_for_operator, const std::vector<uint64_t>& portions, uint64_t expiration_timestamp, const crypto::signature& signature);
bool add_service_node_registration_to_tx_extra(std::vector<uint8_t>& tx_extra, const service_nodes::registration_details& registration);
bool get_tx_secret_key_from_tx_extra(const std::vector<uint8_t>& tx_extra, crypto::secret_key& key);
void add_tx_secret_key_to_tx_extra(std::vector<uint8_t>& tx_extra, const crypto::secret_key& key);
@ -151,16 +153,16 @@ namespace cryptonote
std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const std::vector<uint8_t>& tx_extra);
std::vector<crypto::public_key> get_additional_tx_pub_keys_from_extra(const transaction_prefix& tx);
bool add_additional_tx_pub_keys_to_extra(std::vector<uint8_t>& tx_extra, const std::vector<crypto::public_key>& additional_pub_keys);
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const std::string& extra_nonce);
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, size_t variant_index);
template <typename T>
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra) {
return remove_field_from_tx_extra(tx_extra, tools::template_index<T, tx_extra_field>);
}
void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id);
bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id);
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id);
void set_payment_id_to_tx_extra_nonce(std::string& extra_nonce, const crypto::hash& payment_id);
void set_encrypted_payment_id_to_tx_extra_nonce(std::string& extra_nonce, const crypto::hash8& payment_id);
bool get_payment_id_from_tx_extra_nonce(const std::string& extra_nonce, crypto::hash& payment_id);
bool get_encrypted_payment_id_from_tx_extra_nonce(const std::string& extra_nonce, crypto::hash8& payment_id);
bool add_burned_amount_to_tx_extra(std::vector<uint8_t>& tx_extra, uint64_t burn);
uint64_t get_burned_amount_from_tx_extra(const std::vector<uint8_t>& tx_extra);
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t output_index);
@ -180,18 +182,16 @@ namespace cryptonote
crypto::hash get_blob_hash(const std::string_view blob);
std::string short_hash_str(const crypto::hash& h);
bool get_registration_hash(const std::vector<cryptonote::account_public_address>& addresses, uint64_t operator_portions, const std::vector<uint64_t>& portions, uint64_t expiration_timestamp, crypto::hash& hash);
crypto::hash get_transaction_hash(const transaction& t);
bool get_transaction_hash(const transaction& t, crypto::hash& res);
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size);
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size);
bool calculate_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob, crypto::hash& res);
crypto::hash get_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob = NULL);
bool calculate_transaction_prunable_hash(const transaction& t, const std::string *blob, crypto::hash& res);
crypto::hash get_transaction_prunable_hash(const transaction& t, const std::string *blob = NULL);
bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size);
crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash);
blobdata get_block_hashing_blob(const block& b);
std::string get_block_hashing_blob(const block& b);
bool calculate_block_hash(const block& b, crypto::hash& res);
bool get_block_hash(const block& b, crypto::hash& res);
crypto::hash get_block_hash(const block& b);
@ -202,7 +202,7 @@ namespace cryptonote
uint64_t get_outs_money_amount(const transaction& tx);
bool check_inputs_types_supported(const transaction& tx);
bool check_outs_valid(const transaction& tx);
bool parse_amount(uint64_t& amount, std::string_view str_amount);
std::optional<uint64_t> parse_amount(std::string_view str_amount);
uint64_t get_transaction_weight(const transaction &tx);
uint64_t get_transaction_weight(const transaction &tx, size_t blob_size);
uint64_t get_pruned_transaction_weight(const transaction &tx);
@ -213,8 +213,12 @@ namespace cryptonote
uint64_t get_block_height(const block& b);
std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off);
std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off);
inline constexpr std::string_view get_unit() { return "OXEN"sv; }
std::string print_money(uint64_t amount, bool trim_insignificant = false);
constexpr std::string_view get_unit() { return "OXEN"sv; }
// Returns a monetary value with a decimal point; optionally strips insignificant trailing 0s.
std::string print_money(uint64_t amount, bool strip_zeros = false);
// Returns a formatted monetary value including the unit, e.g. "1.234567 OXEN"; strips
// insignificant trailing 0s by default (unlike the above) but can be overridden to not do that.
std::string format_money(uint64_t amount, bool strip_zeros = true);
std::string print_tx_verification_context (tx_verification_context const &tvc, transaction const *tx = nullptr);
std::string print_vote_verification_context(vote_verification_context const &vvc, service_nodes::quorum_vote_t const *vote = nullptr);
@ -251,7 +255,7 @@ namespace cryptonote
//---------------------------------------------------------------
template <typename T>
bool t_serializable_object_from_blob(T& to, const blobdata& blob)
bool t_serializable_object_from_blob(T& to, const std::string& blob)
{
try {
serialization::parse_binary(blob, to);
@ -262,7 +266,7 @@ namespace cryptonote
}
//---------------------------------------------------------------
template <typename T>
bool t_serializable_object_to_blob(T& val, blobdata& blob)
bool t_serializable_object_to_blob(T& val, std::string& blob)
{
try {
blob = serialization::dump_binary(const_cast<std::remove_const_t<T>&>(val));
@ -275,9 +279,9 @@ namespace cryptonote
}
//---------------------------------------------------------------
template <typename T>
blobdata t_serializable_object_to_blob(const T& val)
std::string t_serializable_object_to_blob(const T& val)
{
blobdata b;
std::string b;
t_serializable_object_to_blob(val, b);
return b;
}
@ -298,7 +302,7 @@ namespace cryptonote
template <typename T>
bool get_object_hash(const T& o, crypto::hash& res, size_t& blob_size)
{
blobdata bl;
std::string bl;
if (!t_serializable_object_to_blob(o, bl))
return false;
blob_size = bl.size();
@ -320,10 +324,10 @@ namespace cryptonote
return ss.str();
}
//---------------------------------------------------------------
blobdata block_to_blob(const block& b);
bool block_to_blob(const block& b, blobdata& b_blob);
blobdata tx_to_blob(const transaction& b);
bool tx_to_blob(const transaction& b, blobdata& b_blob);
std::string block_to_blob(const block& b);
bool block_to_blob(const block& b, std::string& b_blob);
std::string tx_to_blob(const transaction& b);
bool tx_to_blob(const transaction& b, std::string& b_blob);
void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h);
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes);
crypto::hash get_tx_tree_hash(const block& b);

View File

@ -128,13 +128,13 @@ namespace cryptonote {
timestamps.push_back(timestamp);
difficulties.push_back(cumulative_difficulty);
bool before_hf16 = !is_hard_fork_at_least(nettype, network_version_16_pulse, chain_height);
bool before_hf16 = !is_hard_fork_at_least(nettype, hf::hf16_pulse, chain_height);
// Trim down arrays
while (timestamps.size() > DIFFICULTY_BLOCKS_COUNT(before_hf16))
while (timestamps.size() > old::DIFFICULTY_BLOCKS_COUNT(before_hf16))
timestamps.erase(timestamps.begin());
while (difficulties.size() > DIFFICULTY_BLOCKS_COUNT(before_hf16))
while (difficulties.size() > old::DIFFICULTY_BLOCKS_COUNT(before_hf16))
difficulties.erase(difficulties.begin());
}
@ -167,15 +167,15 @@ namespace cryptonote {
{
auto result = difficulty_calc_mode::normal;
if (!is_hard_fork_at_least(nettype, cryptonote::network_version_10_bulletproofs, height))
if (!is_hard_fork_at_least(nettype, hf::hf10_bulletproofs, height))
result = difficulty_calc_mode::use_old_lwma;
// HF12 switches to RandomX with a likely drastically reduced hashrate versus Turtle, so override
// difficulty for the first difficulty window blocks:
else if (auto randomx_start_height = get_hard_fork_heights(nettype, network_version_12_checkpointing).first;
randomx_start_height && height >= *randomx_start_height && height <= *randomx_start_height + DIFFICULTY_WINDOW)
else if (auto randomx_start_height = get_hard_fork_heights(nettype, hf::hf12_checkpointing).first;
randomx_start_height && height >= *randomx_start_height && height <= *randomx_start_height + old::DIFFICULTY_WINDOW)
result = difficulty_calc_mode::hf12_override;
else if (auto pulse_start_height = get_hard_fork_heights(nettype, network_version_16_pulse).first;
nettype == MAINNET && pulse_start_height && height >= *pulse_start_height && height <= *pulse_start_height + DIFFICULTY_WINDOW)
else if (auto pulse_start_height = get_hard_fork_heights(nettype, hf::hf16_pulse).first;
nettype == network_type::MAINNET && pulse_start_height && height >= *pulse_start_height && height <= *pulse_start_height + old::DIFFICULTY_WINDOW)
result = difficulty_calc_mode::hf16_override;
return result;
@ -187,7 +187,7 @@ namespace cryptonote {
difficulty_calc_mode mode)
{
const int64_t T = static_cast<int64_t>(target_seconds);
size_t N = DIFFICULTY_WINDOW;
size_t N = old::DIFFICULTY_WINDOW;
// Return a difficulty of 1 for first 4 blocks if it's the start of the chain.
if (timestamps.size() < 4) {

View File

@ -35,52 +35,57 @@ namespace cryptonote {
// version 7 from the start of the blockchain, inhereted from Monero mainnet
static constexpr std::array mainnet_hard_forks =
{
hard_fork{7, 0, 0, 1503046577 }, // Loki 0.1: Loki is born
hard_fork{8, 0, 64324, 1533006000 /*2018-07-31 03:00 UTC*/ }, // Loki 0.2: New emissions schedule
hard_fork{9, 0, 101250, 1537444800 /*2018-09-20 12:00 UTC*/ }, // Loki 1: Service nodes launched
hard_fork{10, 0, 161849, 1544743800 /*2018-12-13 23:30 UTC*/ }, // Loki 2: Bulletproofs, gov fee batching
hard_fork{11, 0, 234767, 1554170400 /*2019-03-26 13:00 AEDT*/ }, // Loki 3: Infinite staking, CN-Turtle
hard_fork{12, 0, 321467, 1563940800 /*2019-07-24 14:00 AEDT*/ }, // Loki 4: Checkpointing, RandomXL, decommissioning, Storage Server launched
hard_fork{13, 0, 385824, 1571850000 /*2019-10-23 19:00 AEDT*/ }, // Loki 5: Checkpointing enforced
hard_fork{14, 0, 442333, 1578528000 /*2020-01-09 00:00 UTC*/ }, // Loki 6: Blink, Lokinet launched on mainnet
hard_fork{15, 0, 496969, 1585105200 /*2020-03-25 14:00 AEDT (03:00 UTC)*/ }, // Loki 7: ONS (Session)
hard_fork{16, 0, 641111, 1602464400 /*2020-10-12 12:00 AEDT (01:00 UTC)*/ }, // Loki 8: Pulse
hard_fork{17, 0, 770711, 1618016400 /*Saturday, April 10, 2021 1:00:00 UTC*/ }, // Oxen 8: Eliminate 6/block emissions after 180 days (not a separate release)
hard_fork{18, 0, 785000, 1619736143 /*Thursday, April 29, 2021 22:42:23 UTC*/ }, // Oxen 9: Timesync, new proofs, reasons, wallet ONS
hard_fork{18, 1, 839009, 1626217200 /*Tuesday, July 13, 2021 23:00 UTC */ }, // Oxen 9.2: mandatory SS 2.2.0 & lokinet 0.9.5 updates
hard_fork{hf::hf7, 0, 0, 1503046577 }, // Loki 0.1: Loki is born
hard_fork{hf::hf8, 0, 64324, 1533006000 /*2018-07-31 03:00 UTC*/ }, // Loki 0.2: New emissions schedule
hard_fork{hf::hf9_service_nodes, 0, 101250, 1537444800 /*2018-09-20 12:00 UTC*/ }, // Loki 1: Service nodes launched
hard_fork{hf::hf10_bulletproofs, 0, 161849, 1544743800 /*2018-12-13 23:30 UTC*/ }, // Loki 2: Bulletproofs, gov fee batching
hard_fork{hf::hf11_infinite_staking, 0, 234767, 1554170400 /*2019-03-26 13:00 AEDT*/ }, // Loki 3: Infinite staking, CN-Turtle
hard_fork{hf::hf12_checkpointing, 0, 321467, 1563940800 /*2019-07-24 14:00 AEDT*/ }, // Loki 4: Checkpointing, RandomXL, decommissioning, Storage Server launched
hard_fork{hf::hf13_enforce_checkpoints, 0, 385824, 1571850000 /*2019-10-23 19:00 AEDT*/ }, // Loki 5: Checkpointing enforced
hard_fork{hf::hf14_blink, 0, 442333, 1578528000 /*2020-01-09 00:00 UTC*/ }, // Loki 6: Blink, Lokinet launched on mainnet
hard_fork{hf::hf15_ons, 0, 496969, 1585105200 /*2020-03-25 14:00 AEDT (03:00 UTC)*/ }, // Loki 7: ONS (Session)
hard_fork{hf::hf16_pulse, 0, 641111, 1602464400 /*2020-10-12 12:00 AEDT (01:00 UTC)*/ }, // Loki 8: Pulse
hard_fork{hf::hf17, 0, 770711, 1618016400 /*Saturday, April 10, 2021 1:00:00 UTC*/ }, // Oxen 8: Eliminate 6/block emissions after 180 days (not a separate release)
hard_fork{hf::hf18, 0, 785000, 1619736143 /*Thursday, April 29, 2021 22:42:23 UTC*/ }, // Oxen 9: Timesync, new proofs, reasons, wallet ONS
hard_fork{hf::hf18, 1, 839009, 1626217200 /*Tuesday, July 13, 2021 23:00 UTC */ }, // Oxen 9.2: mandatory SS 2.2.0 & lokinet 0.9.5 updates
hard_fork{hf::hf19_reward_batching, 0, 1080149, 1655154000 /*Monday, June 13, 2022 21:00 UTC */}, // Oxen 10.1: Service Node Reward Batching
hard_fork{hf::hf19_reward_batching, 1, 1090229, 1656363600 /*Monday, June 27, 2022 21:00 UTC */}, // Minor hardfork, upgrades to session.
};
static constexpr std::array testnet_hard_forks =
{
hard_fork{7, 0, 0, 1533631121 }, // Testnet was rebooted during Loki 3 development
hard_fork{8, 0, 2, 1533631122 },
hard_fork{9, 0, 3, 1533631123 },
hard_fork{10, 0, 4, 1542681077 },
hard_fork{11, 0, 5, 1551223964 },
hard_fork{12, 0, 75471, 1561608000 }, // 2019-06-28 14:00 AEDT
hard_fork{13, 0, 127028, 1568440800 }, // 2019-09-13 16:00 AEDT
hard_fork{14, 0, 174630, 1575075600 }, // 2019-11-30 07:00 UTC
hard_fork{15, 0, 244777, 1583940000 }, // 2020-03-11 15:20 UTC
hard_fork{16, 0, 382222, 1600468200 }, // 2020-09-18 22:30 UTC
hard_fork{17, 0, 447275, 1608276840 }, // 2020-12-18 05:34 UTC
hard_fork{18, 0, 501750, 1616631051 }, // 2021-03-25 12:10 UTC
hard_fork{18, 1, 578637, 1624040400 }, // 2021-06-18 18:20 UTC
hard_fork{hf::hf7, 0, 0, 1653632397}, // Testnet was rebooted during HF19 - Oxen 10
hard_fork{hf::hf11_infinite_staking, 0, 2, 1653632397},
hard_fork{hf::hf12_checkpointing, 0, 3, 1653632397},
hard_fork{hf::hf13_enforce_checkpoints, 0, 4, 1653632397},
hard_fork{hf::hf14_blink, 0, 5, 1653632397},
hard_fork{hf::hf15_ons, 0, 6, 1653632397},
hard_fork{hf::hf16_pulse, 0, 200, 1653632397},
hard_fork{hf::hf17, 0, 251, 1653632397},
hard_fork{hf::hf18, 0, 252, 1653632397},
hard_fork{hf::hf19_reward_batching, 0, 253, 1653632397},
hard_fork{hf::hf19_reward_batching, 1, 254, 1653632397}, // 2022-05-27T06:19:57.000Z UTC
};
static constexpr std::array devnet_hard_forks =
{
hard_fork{ 7, 0, 0, 1599848400 },
hard_fork{ 11, 0, 2, 1599848400 },
hard_fork{ 12, 0, 3, 1599848400 },
hard_fork{ 13, 0, 4, 1599848400 },
hard_fork{ 15, 0, 5, 1599848400 },
hard_fork{ 16, 0, 99, 1599848400 },
hard_fork{hf::hf7, 0, 0, 1653500577},
hard_fork{hf::hf11_infinite_staking, 0, 2, 1653500577},
hard_fork{hf::hf12_checkpointing, 0, 3, 1653500577},
hard_fork{hf::hf13_enforce_checkpoints, 0, 4, 1653500577},
hard_fork{hf::hf14_blink, 0, 5, 1653500577},
hard_fork{hf::hf15_ons, 0, 6, 1653500577},
hard_fork{hf::hf16_pulse, 0, 100, 1653500577},
hard_fork{hf::hf17, 0, 151, 1653500577},
hard_fork{hf::hf18, 0, 152, 1653500577},
hard_fork{hf::hf19_reward_batching, 0, 153, 1653500577},
hard_fork{hf::hf19_reward_batching, 1, 154, 1653500577},
};
template <size_t N>
static constexpr bool is_ordered(const std::array<hard_fork, N>& forks) {
if (N == 0 || forks[0].version < 7)
if (N == 0 || forks[0].version < hf::hf7)
return false;
for (size_t i = 1; i < N; i++) {
auto& hf = forks[i];
@ -112,9 +117,8 @@ std::pair<const hard_fork*, const hard_fork*> get_hard_forks(network_type type)
return {nullptr, nullptr};
}
std::pair<std::optional<uint64_t>, std::optional<uint64_t>>
get_hard_fork_heights(network_type nettype, uint8_t version) {
get_hard_fork_heights(network_type nettype, hf version) {
std::pair<std::optional<uint64_t>, std::optional<uint64_t>> found;
for (auto [it, end] = get_hard_forks(nettype); it != end; it++) {
if (it->version > version) { // This (and anything else) are in the future
@ -128,7 +132,7 @@ get_hard_fork_heights(network_type nettype, uint8_t version) {
return found;
}
uint8_t hard_fork_ceil(network_type nettype, uint8_t version) {
hf hard_fork_ceil(network_type nettype, hf version) {
auto [it, end] = get_hard_forks(nettype);
for (; it != end; it++)
if (it->version >= version)
@ -137,9 +141,9 @@ uint8_t hard_fork_ceil(network_type nettype, uint8_t version) {
return version;
}
std::pair<uint8_t, uint8_t>
std::pair<hf, uint8_t>
get_network_version_revision(network_type nettype, uint64_t height) {
std::pair<uint8_t, uint8_t> result;
std::pair<hf, uint8_t> result;
for (auto [it, end] = get_hard_forks(nettype); it != end; it++) {
if (it->height <= height)
result = {it->version, it->snode_revision};
@ -149,22 +153,23 @@ get_network_version_revision(network_type nettype, uint64_t height) {
return result;
}
bool is_hard_fork_at_least(network_type type, uint8_t version, uint64_t height) {
bool is_hard_fork_at_least(network_type type, hf version, uint64_t height) {
return get_network_version(type, height) >= version;
}
std::pair<uint8_t, uint8_t>
std::pair<hf, uint8_t>
get_ideal_block_version(network_type nettype, uint64_t height)
{
std::pair<uint8_t, uint8_t> result;
std::pair<hf, uint8_t> result;
for (auto [it, end] = get_hard_forks(nettype); it != end; it++) {
if (it->height <= height)
if (it->height <= height) {
result.first = it->version;
result.second = it->version;
result.second = it->snode_revision;
}
if (result.first < hf::hf19_reward_batching)
result.second = static_cast<uint8_t>(it->version);
}
return result;
}
}
} // namespace cryptonote

View File

@ -35,7 +35,7 @@ namespace cryptonote
// Defines where hard fork (i.e. new minimum network versions) begin
struct hard_fork {
uint8_t version; // Blockchain major version
hf version; // Blockchain major version
uint8_t snode_revision; // Snode revision for enforcing non-blockchain-breaking mandatory service node updates
uint64_t height;
time_t time;
@ -53,7 +53,7 @@ namespace cryptonote
// outdated), and returns nullopt for B if the version indicates that top network version we know
// about (i.e. there is no subsequent hardfork scheduled).
std::pair<std::optional<uint64_t>, std::optional<uint64_t>>
get_hard_fork_heights(network_type type, uint8_t version);
get_hard_fork_heights(network_type type, hf version);
// Returns the lowest network version >= the given version, that is, it rounds up missing hf table
// entries to the next largest entry. Typically this returns the network version itself, but if
@ -68,18 +68,18 @@ namespace cryptonote
// ...
// hard_fork_ceil(14) == 14
// hard_fork_ceil(15) == 15
uint8_t hard_fork_ceil(network_type type, uint8_t version);
hf hard_fork_ceil(network_type type, hf version);
// Returns true if the given height is sufficiently high to be at or after the given hard fork
// version.
bool is_hard_fork_at_least(network_type type, uint8_t version, uint64_t height);
bool is_hard_fork_at_least(network_type type, hf version, uint64_t height);
// Returns the active network version and snode revision for the given height.
std::pair<uint8_t, uint8_t>
std::pair<hf, uint8_t>
get_network_version_revision(network_type nettype, uint64_t height);
// Returns the network (i.e. block) version for the given height.
inline uint8_t get_network_version(network_type nettype, uint64_t height) {
inline hf get_network_version(network_type nettype, uint64_t height) {
return get_network_version_revision(nettype, height).first;
}
@ -87,14 +87,16 @@ namespace cryptonote
// a shortcut for `get_hard_fork_heights(type, hard_fork_ceil(type, version)).first`, i.e. it
// returns the first height at which `version` rules become active (even if they became active at
// a hard fork > the given value).
inline std::optional<uint64_t> hard_fork_begins(network_type type, uint8_t version) {
inline std::optional<uint64_t> hard_fork_begins(network_type type, hf version) {
return get_hard_fork_heights(type, hard_fork_ceil(type, version)).first;
}
// Returns the "ideal" network version that we want to use on blocks we create, which is to use
// the required major version for major version and the maximum major version we know about as
// minor version. If this seems a bit silly, it is, and will be changed in the future.
std::pair<uint8_t, uint8_t> get_ideal_block_version(network_type nettype, uint64_t height);
// the required major version and current minor version. (Minor versions are sometimes used to
// change network features, but do not change the blockchain rules).
// Before HF19, the minor version must be >= the major version, and is set to the largest major
// version we know about.
std::pair<hf, uint8_t> get_ideal_block_version(network_type nettype, uint64_t height);
} // namespace cryptonote

Some files were not shown because too many files have changed in this diff Show More