Compare commits
117 Commits
v0.5.2
...
v0.9.6-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
| 9d9471d314 | |||
| 5da798a7c5 | |||
| 0f97ec9ea7 | |||
| 0418bfee30 | |||
| 488d5f1e9b | |||
| 771b8ea606 | |||
| 28262a30fe | |||
| aa4276c39e | |||
| 1f49c178ee | |||
| f087b3807b | |||
| cb6cdac603 | |||
| 082976a3f0 | |||
| 420824005e | |||
| 98ded9b9c4 | |||
| 9baeb750ac | |||
| 1cf81058b6 | |||
| 9570c7a910 | |||
| 23756691b7 | |||
| d5f6cdc0cd | |||
| 378ec75a6e | |||
| 3eb986fc51 | |||
| b713a08a81 | |||
| 5bd079af4a | |||
| cd2c7c939c | |||
| 2f707e30c6 | |||
| f9726354b8 | |||
| fcd78eea7e | |||
| db740fa037 | |||
| 5971f39e7a | |||
| 02f2eb5ee9 | |||
| 02ef77bbcc | |||
| aa64124c28 | |||
| bc7db51f03 | |||
| 6889321361 | |||
| 3cb473132e | |||
| b298f542a6 | |||
| eb9f799b8b | |||
| 8bf35db67e | |||
| aeef1a6677 | |||
| ee586a3fca | |||
| 19be3a6146 | |||
| 64a69268fe | |||
| 7312652540 | |||
| 8cd587ec54 | |||
| 62c43a4ed2 | |||
| 0180051a8c | |||
| a7c1ba652b | |||
| 2a4d08b67f | |||
| 3fc5ea3543 | |||
| 3b72dc0555 | |||
| b48c86afe0 | |||
| 0f88d91fa0 | |||
| f4612357b2 | |||
| e9a2b6fbb7 | |||
| ca2069facc | |||
| 114297d784 | |||
| 6368aee05f | |||
| 8599cdf95b | |||
| d39f2f180e | |||
| c763febe98 | |||
| cef01372b1 | |||
| e15dbb5db2 | |||
| 82d706aacb | |||
| f3522764a1 | |||
| 0448a6bf9a | |||
| 2ce22c2508 | |||
| 1334bac45a | |||
| e909e3eef1 | |||
| 4b594142ca | |||
| 29e435bd39 | |||
| 4abde92c1a | |||
| dd23331df9 | |||
| 7d2025bc19 | |||
| a01422a5e0 | |||
| e68f7f46ed | |||
| b87c243da1 | |||
| 49fd907073 | |||
| 8c999520d1 | |||
| 945bdc72e7 | |||
| c6d843b6f5 | |||
| 8f5111aeda | |||
| b285ec550d | |||
| afc2518ef7 | |||
| a9406b158d | |||
| e45643e157 | |||
| 1df18ca6a4 | |||
| 91b2ec275a | |||
| e45fdb863c | |||
| cb2f9d3f75 | |||
| 59025bb27b | |||
| 204c6fc778 | |||
| 78c2b4b1fb | |||
| fcac456902 | |||
| 1824a34a68 | |||
| 1786c628bf | |||
| 6b8df3cee5 | |||
| 884db2b499 | |||
| ce7a1bdd96 | |||
| 57cbb146db | |||
| 85c856411e | |||
| 6fefb49da0 | |||
| c5c828516b | |||
| 218911d9fc | |||
| da3ef2511d | |||
| 8b2b039036 | |||
| 4d1c84fcaf | |||
| bb91b01cf7 | |||
| 7f0eda828a | |||
| d3f15211d7 | |||
| b828703bbd | |||
| 2fa8ef97ef | |||
| acb3af43f0 | |||
| d1eed6e9ff | |||
| 30a2931067 | |||
| 1c73dd0c9f | |||
| 1c84c00fe6 | |||
| 7abf28d87c |
@@ -0,0 +1,127 @@
|
||||
name: ci/gh-actions/depends
|
||||
|
||||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**/README.md'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '**/README.md'
|
||||
|
||||
env:
|
||||
APT_SET_CONF: |
|
||||
echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
|
||||
echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
|
||||
echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
|
||||
CCACHE_SETTINGS: |
|
||||
ccache --max-size=150M
|
||||
ccache --set-config=compression=true
|
||||
USE_DEVICE_TREZOR_MANDATORY: ON
|
||||
|
||||
jobs:
|
||||
build-cross:
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
CCACHE_TEMPDIR: /tmp/.ccache-temp
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
toolchain:
|
||||
- name: "RISCV 64bit"
|
||||
host: "riscv64-linux-gnu"
|
||||
packages: "python3 gperf g++-riscv64-linux-gnu"
|
||||
- name: "ARM v7"
|
||||
host: "arm-linux-gnueabihf"
|
||||
packages: "python3 gperf g++-arm-linux-gnueabihf"
|
||||
- name: "ARM v8"
|
||||
host: "aarch64-linux-gnu"
|
||||
packages: "python3 gperf g++-aarch64-linux-gnu"
|
||||
- name: "i686 Win"
|
||||
host: "i686-w64-mingw32"
|
||||
packages: "python3 g++-mingw-w64-i686"
|
||||
- name: "i686 Linux"
|
||||
host: "i686-pc-linux-gnu"
|
||||
packages: "gperf cmake g++-multilib python3-zmq"
|
||||
- name: "Win64"
|
||||
host: "x86_64-w64-mingw32"
|
||||
packages: "cmake python3 g++-mingw-w64-x86-64"
|
||||
- name: "x86_64 Linux"
|
||||
host: "x86_64-unknown-linux-gnu"
|
||||
packages: "gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
|
||||
- name: "Cross-Mac x86_64"
|
||||
host: "x86_64-apple-darwin"
|
||||
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
|
||||
- name: "Cross-Mac aarch64"
|
||||
host: "aarch64-apple-darwin"
|
||||
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
|
||||
- name: "x86_64 Freebsd"
|
||||
host: "x86_64-unknown-freebsd"
|
||||
packages: "clang-8 gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
|
||||
# - name: "ARMv8 Android"
|
||||
# host: "aarch64-linux-android"
|
||||
# packages: "gperf cmake python3"
|
||||
name: ${{ matrix.toolchain.name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
# Most volatile cache
|
||||
- name: ccache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ccache-${{ matrix.toolchain.host }}-${{ github.sha }}
|
||||
restore-keys: ccache-${{ matrix.toolchain.host }}-
|
||||
# Less volatile cache
|
||||
- name: depends cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: contrib/depends/built
|
||||
key: depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
|
||||
restore-keys: |
|
||||
depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
|
||||
depends-${{ matrix.toolchain.host }}-
|
||||
# Static cache
|
||||
- name: OSX SDK cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: contrib/depends/sdk-sources
|
||||
key: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
|
||||
restore-keys: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
|
||||
- name: set apt conf
|
||||
run: ${{env.APT_SET_CONF}}
|
||||
- name: install dependencies
|
||||
run: sudo apt update; sudo apt -y install build-essential libtool libssl-dev cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache ${{ matrix.toolchain.packages }}
|
||||
- name: prepare w64-mingw32
|
||||
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'i686-w64-mingw32' }}
|
||||
run: |
|
||||
sudo update-alternatives --set ${{ matrix.toolchain.host }}-g++ $(which ${{ matrix.toolchain.host }}-g++-posix)
|
||||
sudo update-alternatives --set ${{ matrix.toolchain.host }}-gcc $(which ${{ matrix.toolchain.host }}-gcc-posix)
|
||||
- name: build
|
||||
run: |
|
||||
${{env.CCACHE_SETTINGS}}
|
||||
make depends target=${{ matrix.toolchain.host }} -j2
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin' || matrix.toolchain.host == 'aarch64-apple-darwin' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
|
||||
with:
|
||||
name: ${{ matrix.toolchain.name }}
|
||||
path: |
|
||||
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-*
|
||||
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salviumd*
|
||||
- name: zip daemon & cli
|
||||
run: |
|
||||
zip salvium-${GITHUB_REF_NAME}-${{ matrix.toolchain.host }}.zip /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-rpc* /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-cli* /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salviumd*
|
||||
ls -l
|
||||
- name: "Deploy"
|
||||
uses: keithweaver/aws-s3-github-action@v1.0.0
|
||||
with:
|
||||
command: cp
|
||||
source: ./salvium-${{ github.ref_name }}-${{ matrix.toolchain.host }}.zip
|
||||
destination: s3://${{ vars.S3_BUCKET }}/salvium-${{ github.ref_name }}-${{ matrix.toolchain.host }}.zip
|
||||
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
aws_region: eu-west-1
|
||||
flags: --acl public-read
|
||||
@@ -30,6 +30,9 @@ contrib/gitian/builder/
|
||||
contrib/gitian/docker/
|
||||
contrib/gitian/sigs/
|
||||
|
||||
# Audit tool
|
||||
src/blockchain_utilities/blockchain_audit.cpp
|
||||
|
||||
# Created by https://www.gitignore.io
|
||||
|
||||
### C++ ###
|
||||
|
||||
@@ -14,3 +14,6 @@
|
||||
[submodule "external/miniupnp"]
|
||||
path = external/miniupnp
|
||||
url = https://github.com/miniupnp/miniupnp
|
||||
[submodule "external/mx25519"]
|
||||
path = external/mx25519
|
||||
url = https://github.com/tevador/mx25519
|
||||
|
||||
+18
-7
@@ -531,14 +531,14 @@ add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}")
|
||||
# Can't install hook in static build on OSX, because OSX linker does not support --wrap
|
||||
# On ARM, having libunwind package (with .so's only) installed breaks static link.
|
||||
# When possible, avoid stack tracing using libunwind in favor of using easylogging++.
|
||||
if (APPLE OR NETBSD)
|
||||
if (APPLE)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
elseif (DEPENDS AND NOT LINUX)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(DEFAULT_STACK_TRACE ON)
|
||||
set(STACK_TRACE_LIB "easylogging++") # for diag output only
|
||||
set(LIBUNWIND_LIBRARIES "")
|
||||
elseif (ARM)
|
||||
@@ -547,7 +547,7 @@ elseif (ARM)
|
||||
else()
|
||||
find_package(Libunwind)
|
||||
if(LIBUNWIND_FOUND)
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
set(DEFAULT_STACK_TRACE ON)
|
||||
set(STACK_TRACE_LIB "libunwind") # for diag output only
|
||||
else()
|
||||
set(DEFAULT_STACK_TRACE OFF)
|
||||
@@ -1084,6 +1084,7 @@ endif()
|
||||
find_package(Boost 1.58 QUIET REQUIRED COMPONENTS ${BOOST_COMPONENTS})
|
||||
add_definitions(-DBOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
|
||||
add_definitions(-DBOOST_NO_AUTO_PTR)
|
||||
add_definitions(-DBOOST_UUID_DISABLE_ALIGNMENT) # This restores UUID's std::has_unique_object_representations property
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES})
|
||||
if(NOT Boost_FOUND)
|
||||
@@ -1107,7 +1108,9 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||
if(MINGW)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj")
|
||||
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt)
|
||||
if(NOT DEPENDS)
|
||||
if(DEPENDS)
|
||||
set(ICU_LIBRARIES icuio icui18n icuuc icudata icutu iconv)
|
||||
else()
|
||||
set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv)
|
||||
endif()
|
||||
elseif(APPLE OR OPENBSD OR ANDROID)
|
||||
@@ -1182,7 +1185,6 @@ endif()
|
||||
if(STATIC)
|
||||
set(sodium_USE_STATIC_LIBS ON)
|
||||
endif()
|
||||
find_package(Sodium REQUIRED)
|
||||
|
||||
find_path(ZMQ_INCLUDE_PATH zmq.h)
|
||||
find_library(ZMQ_LIB zmq)
|
||||
@@ -1190,6 +1192,7 @@ find_library(PGM_LIBRARY pgm)
|
||||
find_library(NORM_LIBRARY norm)
|
||||
find_library(GSSAPI_LIBRARY gssapi_krb5)
|
||||
find_library(PROTOLIB_LIBRARY protolib)
|
||||
find_library(SODIUM_LIBRARY sodium)
|
||||
find_library(BSD_LIBRARY bsd)
|
||||
find_library(MD_LIBRARY md)
|
||||
find_library(PROTOKIT_LIBRARY protokit)
|
||||
@@ -1212,8 +1215,16 @@ endif()
|
||||
if(PROTOLIB_LIBRARY)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${PROTOLIB_LIBRARY}")
|
||||
endif()
|
||||
if(Sodium_FOUND)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${sodium_LIBRARIES}")
|
||||
if(SODIUM_LIBRARY)
|
||||
message(STATUS "ZMQ_LIB: ${ZMQ_LIB};${SODIUM_LIBRARY}")
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${SODIUM_LIBRARY}")
|
||||
find_path(SODIUM_INCLUDE_PATH sodium/crypto_verify_32.h)
|
||||
if (SODIUM_INCLUDE_PATH)
|
||||
message(STATUS "SODIUM_INCLUDE_PATH: ${SODIUM_INCLUDE_PATH}")
|
||||
include_directories(${SODIUM_INCLUDE_PATH})
|
||||
else()
|
||||
message(FATAL_ERROR "Could not find required sodium/crypto_verify_32.h")
|
||||
endif()
|
||||
endif()
|
||||
if(BSD_LIBRARY)
|
||||
set(ZMQ_LIB "${ZMQ_LIB};${BSD_LIBRARY}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Salvium Zero v0.4.1
|
||||
# Salvium Zero v0.9.6
|
||||
|
||||
Copyright (c) 2023-2024, Salvium
|
||||
Portions Copyright (c) 2014-2023, The Monero Project
|
||||
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
|
||||
|
||||
```bash
|
||||
cd salvium
|
||||
git checkout release-v0.18
|
||||
git checkout v0.9.6
|
||||
make
|
||||
```
|
||||
|
||||
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
|
||||
```bash
|
||||
git clone https://github.com/salvium/salvium
|
||||
cd salvium
|
||||
git checkout v0.4.1
|
||||
git checkout v0.9.6
|
||||
```
|
||||
|
||||
* Build:
|
||||
@@ -370,10 +370,10 @@ application.
|
||||
cd salvium
|
||||
```
|
||||
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.4.1'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.6'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.4.1
|
||||
git checkout v0.9.6
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
depends_prefix="`dirname ${ac_site_file}`/.."
|
||||
|
||||
cross_compiling=maybe
|
||||
host_alias=@HOST@
|
||||
ac_tool_prefix=${host_alias}-
|
||||
|
||||
if test -z $with_boost; then
|
||||
with_boost=$depends_prefix
|
||||
fi
|
||||
|
||||
if test x@host_os@ = xdarwin; then
|
||||
BREW=no
|
||||
PORT=no
|
||||
fi
|
||||
|
||||
PATH=$depends_prefix/native/bin:$PATH
|
||||
PKG_CONFIG="`which pkg-config` --static"
|
||||
|
||||
# These two need to remain exported because pkg-config does not see them
|
||||
# otherwise. That means they must be unexported at the end of configure.ac to
|
||||
# avoid ruining the cache. Sigh.
|
||||
export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig
|
||||
if test -z "@allow_host_packages@"; then
|
||||
export PKGCONFIG_LIBDIR=
|
||||
fi
|
||||
|
||||
CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS"
|
||||
LDFLAGS="-L$depends_prefix/lib $LDFLAGS"
|
||||
|
||||
CC="@CC@"
|
||||
CXX="@CXX@"
|
||||
OBJC="${CC}"
|
||||
CCACHE=$depends_prefix/native/bin/ccache
|
||||
PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH
|
||||
|
||||
if test -n "@AR@"; then
|
||||
AR=@AR@
|
||||
ac_cv_path_ac_pt_AR=${AR}
|
||||
fi
|
||||
|
||||
if test -n "@RANLIB@"; then
|
||||
RANLIB=@RANLIB@
|
||||
ac_cv_path_ac_pt_RANLIB=${RANLIB}
|
||||
fi
|
||||
|
||||
if test -n "@NM@"; then
|
||||
NM=@NM@
|
||||
ac_cv_path_ac_pt_NM=${NM}
|
||||
fi
|
||||
|
||||
if test -n "@debug@"; then
|
||||
enable_reduce_exports=no
|
||||
fi
|
||||
|
||||
if test -n "@CFLAGS@"; then
|
||||
CFLAGS="@CFLAGS@ $CFLAGS"
|
||||
fi
|
||||
if test -n "@CXXFLAGS@"; then
|
||||
CXXFLAGS="@CXXFLAGS@ $CXXFLAGS"
|
||||
fi
|
||||
if test -n "@CPPFLAGS@"; then
|
||||
CPPFLAGS="@CPPFLAGS@ $CPPFLAGS"
|
||||
fi
|
||||
if test -n "@LDFLAGS@"; then
|
||||
LDFLAGS="@LDFLAGS@ $LDFLAGS"
|
||||
fi
|
||||
@@ -1,8 +1,9 @@
|
||||
package=boost
|
||||
$(package)_version=1_64_0
|
||||
$(package)_download_path=https://downloads.sourceforge.net/project/boost/boost/1.64.0/
|
||||
$(package)_file_name=$(package)_$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332
|
||||
$(package)_version=1.66.0
|
||||
$(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/
|
||||
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz
|
||||
$(package)_sha256_hash=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60
|
||||
$(package)_dependencies=libiconv
|
||||
$(package)_patches=fix_aroptions.patch fix_arm_arch.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
@@ -21,11 +22,10 @@ $(package)_toolset_$(host_os)=gcc
|
||||
$(package)_archiver_$(host_os)=$($(package)_ar)
|
||||
$(package)_toolset_darwin=darwin
|
||||
$(package)_archiver_darwin=$($(package)_libtool)
|
||||
$(package)_config_libraries_$(host_os)="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization"
|
||||
$(package)_config_libraries_mingw32="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale"
|
||||
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
|
||||
$(package)_cxxflags=-std=c++11
|
||||
$(package)_cxxflags_linux=-fPIC
|
||||
$(package)_cxxflags_freebsd=-fPIC
|
||||
$(package)_cxxflags_freebsd=-fPIC -DBOOST_ASIO_HAS_STD_STRING_VIEW=1
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
@@ -35,7 +35,7 @@ define $(package)_preprocess_cmds
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries_$(host_os))
|
||||
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package=icu4c
|
||||
$(package)_version=55.2
|
||||
$(package)_download_path=https://github.com/unicode-org/icu/releases/download/release-55-2/
|
||||
$(package)_file_name=$(package)-55_2-src.tgz
|
||||
$(package)_sha256_hash=eda2aa9f9c787748a2e2d310590720ca8bcc6252adf6b4cfb03b65bef9d66759
|
||||
$(package)_patches=icu-001-dont-build-static-dynamic-twice.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC -DENABLE_STATIC=YES -DPGKDATA_MODE=static"
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/icu-001-dont-build-static-dynamic-twice.patch &&\
|
||||
mkdir builda &&\
|
||||
mkdir buildb &&\
|
||||
cd builda &&\
|
||||
sh ../source/runConfigureICU Linux &&\
|
||||
make &&\
|
||||
cd ../buildb &&\
|
||||
sh ../source/runConfigureICU MinGW --enable-static=yes --disable-shared --disable-layout --disable-layoutex --disable-tests --disable-samples --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\
|
||||
$(MAKE) $($(package)_build_opts)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
cd buildb &&\
|
||||
$(MAKE) $($(package)_build_opts) DESTDIR=$($(package)_staging_dir) install lib/*
|
||||
endef
|
||||
@@ -0,0 +1,35 @@
|
||||
package=libiconv
|
||||
$(package)_version=1.15
|
||||
$(package)_download_path=https://ftp.gnu.org/gnu/libiconv
|
||||
$(package)_file_name=libiconv-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
|
||||
$(package)_patches=fix-whitespace.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--disable-nls
|
||||
$(package)_config_opts=--enable-static
|
||||
$(package)_config_opts=--disable-shared
|
||||
$(package)_config_opts_linux=--with-pic
|
||||
$(package)_config_opts_freebsd=--with-pic
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux/ &&\
|
||||
patch -p1 < $($(package)_patch_dir)/fix-whitespace.patch
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
$($(package)_autoconf) AR_FLAGS=$($(package)_arflags)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm lib/*.la
|
||||
endef
|
||||
@@ -0,0 +1,25 @@
|
||||
package=native_ccache
|
||||
$(package)_version=3.3.4
|
||||
$(package)_download_path=https://samba.org/ftp/ccache
|
||||
$(package)_file_name=ccache-$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
$($(package)_autoconf)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm -rf lib include
|
||||
endef
|
||||
@@ -1,28 +1,38 @@
|
||||
packages:=boost openssl zeromq expat unbound sodium
|
||||
packages:=boost openssl zeromq libiconv expat unbound
|
||||
|
||||
# ccache is useless in gitian builds
|
||||
ifneq ($(GITIAN),1)
|
||||
native_packages := native_ccache
|
||||
endif
|
||||
|
||||
hardware_packages := hidapi protobuf libusb
|
||||
hardware_native_packages := native_protobuf
|
||||
|
||||
android_native_packages = android_ndk $(hardware_native_packages)
|
||||
android_packages = ncurses readline protobuf
|
||||
android_native_packages = android_ndk
|
||||
android_packages = ncurses readline sodium
|
||||
|
||||
darwin_native_packages = $(hardware_native_packages)
|
||||
darwin_packages = ncurses readline $(hardware_packages)
|
||||
darwin_packages = ncurses readline sodium $(hardware_packages)
|
||||
|
||||
# not really native...
|
||||
freebsd_native_packages = freebsd_base $(hardware_native_packages)
|
||||
freebsd_packages = ncurses readline protobuf libusb
|
||||
freebsd_native_packages = freebsd_base
|
||||
freebsd_packages = ncurses readline sodium
|
||||
|
||||
linux_packages = eudev ncurses readline $(hardware_packages)
|
||||
linux_packages = eudev ncurses readline sodium $(hardware_packages)
|
||||
linux_native_packages = $(hardware_native_packages)
|
||||
|
||||
ifeq ($(build_tests),ON)
|
||||
packages += gtest
|
||||
endif
|
||||
|
||||
mingw32_packages = $(hardware_packages)
|
||||
ifneq ($(host_arch),riscv64)
|
||||
linux_packages += unwind
|
||||
endif
|
||||
|
||||
mingw32_packages = icu4c sodium $(hardware_packages)
|
||||
mingw32_native_packages = $(hardware_native_packages)
|
||||
|
||||
ifneq ($(build_os),darwin)
|
||||
darwin_native_packages += darwin_sdk native_clang native_cctools native_libtapi
|
||||
endif
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package=unwind
|
||||
$(package)_version=1.5.0
|
||||
$(package)_download_path=https://download.savannah.nongnu.org/releases/libunwind
|
||||
$(package)_file_name=lib$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=90337653d92d4a13de590781371c604f9031cdb50520366aa1e3a91e1efb1017
|
||||
$(package)_patches=fix_obj_order.patch
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p0 < $($(package)_patch_dir)/fix_obj_order.patch
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
cp -f $(BASEDIR)/config.guess config/config.guess &&\
|
||||
cp -f $(BASEDIR)/config.sub config/config.sub &&\
|
||||
$($(package)_autoconf) --disable-shared --enable-static --disable-tests --disable-documentation AR_FLAGS=$($(package)_arflags)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm lib/*.la
|
||||
endef
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
Don't build object files twice
|
||||
|
||||
When passed --enable-static and --enable-shared, icu will generate
|
||||
both a shared and a static version of its libraries.
|
||||
|
||||
However, in order to do so, it builds each and every object file
|
||||
twice: once with -fPIC (for the shared library), and once without
|
||||
-fPIC (for the static library). While admittedly building -fPIC for a
|
||||
static library generates a slightly suboptimal code, this is what all
|
||||
the autotools-based project are doing. They build each object file
|
||||
once, and they use it for both the static and shared libraries.
|
||||
|
||||
icu builds the object files for the shared library as .o files, and
|
||||
the object files for static library as .ao files. By simply changing
|
||||
the suffix of object files used for static libraries to ".o", we tell
|
||||
icu to use the ones built for the shared library (i.e, with -fPIC),
|
||||
and avoid the double build of icu.
|
||||
|
||||
On a fast build server, this brings the target icu build from
|
||||
3m41.302s down to 1m43.926s (approximate numbers: some other builds
|
||||
are running on the system at the same time).
|
||||
|
||||
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
|
||||
Index: b/source/config/mh-linux
|
||||
===================================================================
|
||||
--- a/source/config/mh-linux
|
||||
+++ b/source/config/mh-linux
|
||||
@@ -38,7 +38,7 @@
|
||||
## Shared object suffix
|
||||
SO = so
|
||||
## Non-shared intermediate object suffix
|
||||
-STATIC_O = ao
|
||||
+STATIC_O = o
|
||||
|
||||
## Compilation rules
|
||||
%.$(STATIC_O): $(srcdir)/%.c
|
||||
@@ -0,0 +1,13 @@
|
||||
diff --git a/preload/configure b/preload/configure
|
||||
index aab5c77..e20b8f0 100755
|
||||
--- a/preload/configure
|
||||
+++ b/preload/configure
|
||||
@@ -588,7 +588,7 @@ MAKEFLAGS=
|
||||
PACKAGE_NAME='libiconv'
|
||||
PACKAGE_TARNAME='libiconv'
|
||||
PACKAGE_VERSION='0'
|
||||
-PACKAGE_STRING='libiconv 0'
|
||||
+PACKAGE_STRING='libiconv0'
|
||||
PACKAGE_BUGREPORT=''
|
||||
PACKAGE_URL=''
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
--- config/ltmain.sh.0 2020-11-10 17:25:26.000000000 +0100
|
||||
+++ config/ltmain.sh 2021-09-11 19:39:36.000000000 +0200
|
||||
@@ -10768,6 +10768,8 @@
|
||||
fi
|
||||
func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
|
||||
tool_oldlib=$func_to_tool_file_result
|
||||
+ oldobjs=`for obj in $oldobjs; do echo $obj; done | sort`
|
||||
+ oldobjs=" `echo $oldobjs`"
|
||||
eval cmds=\"$old_archive_cmds\"
|
||||
|
||||
func_len " $cmds"
|
||||
@@ -74,6 +74,7 @@ namespace epee
|
||||
public:
|
||||
using char_type = std::uint8_t;
|
||||
using Ch = char_type;
|
||||
using value_type = char_type;
|
||||
|
||||
//! Increase internal buffer by at least `byte_stream_increase` bytes.
|
||||
byte_stream() noexcept
|
||||
@@ -86,6 +87,7 @@ namespace epee
|
||||
~byte_stream() noexcept = default;
|
||||
byte_stream& operator=(byte_stream&& rhs) noexcept;
|
||||
|
||||
std::uint8_t* data() noexcept { return buffer_.get(); }
|
||||
const std::uint8_t* data() const noexcept { return buffer_.get(); }
|
||||
std::uint8_t* tellp() const noexcept { return next_write_; }
|
||||
std::size_t available() const noexcept { return end_ - next_write_; }
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <condition_variable>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
@@ -64,6 +65,7 @@
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net"
|
||||
|
||||
#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 1000
|
||||
#define ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT 100 * 1024 * 1024
|
||||
|
||||
namespace epee
|
||||
{
|
||||
@@ -76,6 +78,13 @@ namespace net_utils
|
||||
protected:
|
||||
virtual ~i_connection_filter(){}
|
||||
};
|
||||
|
||||
struct i_connection_limit
|
||||
{
|
||||
virtual bool is_host_limit(const epee::net_utils::network_address &address)=0;
|
||||
protected:
|
||||
virtual ~i_connection_limit(){}
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
@@ -100,8 +109,8 @@ namespace net_utils
|
||||
using ec_t = boost::system::error_code;
|
||||
using handshake_t = boost::asio::ssl::stream_base::handshake_type;
|
||||
|
||||
using io_context_t = boost::asio::io_service;
|
||||
using strand_t = boost::asio::io_service::strand;
|
||||
using io_context_t = boost::asio::io_context;
|
||||
using strand_t = io_context_t::strand;
|
||||
using socket_t = boost::asio::ip::tcp::socket;
|
||||
|
||||
using network_throttle_t = epee::net_utils::network_throttle;
|
||||
@@ -162,6 +171,7 @@ namespace net_utils
|
||||
} read;
|
||||
struct {
|
||||
std::deque<epee::byte_slice> queue;
|
||||
std::size_t total_bytes;
|
||||
bool wait_consume;
|
||||
} write;
|
||||
};
|
||||
@@ -260,20 +270,28 @@ namespace net_utils
|
||||
struct shared_state : connection_basic_shared_state, t_protocol_handler::config_type
|
||||
{
|
||||
shared_state()
|
||||
: connection_basic_shared_state(), t_protocol_handler::config_type(), pfilter(nullptr), stop_signal_sent(false)
|
||||
: connection_basic_shared_state(),
|
||||
t_protocol_handler::config_type(),
|
||||
pfilter(nullptr),
|
||||
plimit(nullptr),
|
||||
response_soft_limit(ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT),
|
||||
stop_signal_sent(false)
|
||||
{}
|
||||
|
||||
i_connection_filter* pfilter;
|
||||
i_connection_limit* plimit;
|
||||
std::size_t response_soft_limit;
|
||||
bool stop_signal_sent;
|
||||
};
|
||||
|
||||
/// Construct a connection with the given io_service.
|
||||
explicit connection( boost::asio::io_service& io_service,
|
||||
/// Construct a connection with the given io_context.
|
||||
explicit connection( io_context_t& io_context,
|
||||
std::shared_ptr<shared_state> state,
|
||||
t_connection_type connection_type,
|
||||
epee::net_utils::ssl_support_t ssl_support);
|
||||
|
||||
explicit connection( boost::asio::ip::tcp::socket&& sock,
|
||||
explicit connection( io_context_t& io_context,
|
||||
boost::asio::ip::tcp::socket&& sock,
|
||||
std::shared_ptr<shared_state> state,
|
||||
t_connection_type connection_type,
|
||||
epee::net_utils::ssl_support_t ssl_support);
|
||||
@@ -306,7 +324,7 @@ namespace net_utils
|
||||
virtual bool close();
|
||||
virtual bool call_run_once_service_io();
|
||||
virtual bool request_callback();
|
||||
virtual boost::asio::io_service& get_io_service();
|
||||
virtual io_context_t& get_io_context();
|
||||
virtual bool add_ref();
|
||||
virtual bool release();
|
||||
//------------------------------------------------------
|
||||
@@ -336,7 +354,7 @@ namespace net_utils
|
||||
/// serve up files from the given directory.
|
||||
|
||||
boosted_tcp_server(t_connection_type connection_type);
|
||||
explicit boosted_tcp_server(boost::asio::io_service& external_io_service, t_connection_type connection_type);
|
||||
explicit boosted_tcp_server(boost::asio::io_context& external_io_context, t_connection_type connection_type);
|
||||
~boosted_tcp_server();
|
||||
|
||||
std::map<std::string, t_connection_type> server_type_map;
|
||||
@@ -349,7 +367,7 @@ namespace net_utils
|
||||
const std::string port_ipv6 = "", const std::string address_ipv6 = "::", bool use_ipv6 = false, bool require_ipv4 = true,
|
||||
ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
|
||||
|
||||
/// Run the server's io_service loop.
|
||||
/// Run the server's io_context loop.
|
||||
bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes());
|
||||
|
||||
/// wait for service workers stop
|
||||
@@ -369,6 +387,8 @@ namespace net_utils
|
||||
size_t get_threads_count(){return m_threads_count;}
|
||||
|
||||
void set_connection_filter(i_connection_filter* pfilter);
|
||||
void set_connection_limit(i_connection_limit* plimit);
|
||||
void set_response_soft_limit(std::size_t limit);
|
||||
|
||||
void set_default_remote(epee::net_utils::network_address remote)
|
||||
{
|
||||
@@ -409,7 +429,7 @@ namespace net_utils
|
||||
return connections_count;
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service(){return io_service_;}
|
||||
boost::asio::io_context& get_io_context(){return io_context_;}
|
||||
|
||||
struct idle_callback_conext_base
|
||||
{
|
||||
@@ -417,7 +437,7 @@ namespace net_utils
|
||||
|
||||
virtual bool call_handler(){return true;}
|
||||
|
||||
idle_callback_conext_base(boost::asio::io_service& io_serice):
|
||||
idle_callback_conext_base(boost::asio::io_context& io_serice):
|
||||
m_timer(io_serice)
|
||||
{}
|
||||
boost::asio::deadline_timer m_timer;
|
||||
@@ -426,7 +446,7 @@ namespace net_utils
|
||||
template <class t_handler>
|
||||
struct idle_callback_conext: public idle_callback_conext_base
|
||||
{
|
||||
idle_callback_conext(boost::asio::io_service& io_serice, t_handler& h, uint64_t period):
|
||||
idle_callback_conext(boost::asio::io_context& io_serice, t_handler& h, uint64_t period):
|
||||
idle_callback_conext_base(io_serice),
|
||||
m_handler(h)
|
||||
{this->m_period = period;}
|
||||
@@ -442,7 +462,7 @@ namespace net_utils
|
||||
template<class t_handler>
|
||||
bool add_idle_handler(t_handler t_callback, uint64_t timeout_ms)
|
||||
{
|
||||
boost::shared_ptr<idle_callback_conext<t_handler>> ptr(new idle_callback_conext<t_handler>(io_service_, t_callback, timeout_ms));
|
||||
boost::shared_ptr<idle_callback_conext<t_handler>> ptr(new idle_callback_conext<t_handler>(io_context_, t_callback, timeout_ms));
|
||||
//needed call handler here ?...
|
||||
ptr->m_timer.expires_from_now(boost::posix_time::milliseconds(ptr->m_period));
|
||||
ptr->m_timer.async_wait(boost::bind(&boosted_tcp_server<t_protocol_handler>::global_timer_handler<t_handler>, this, ptr));
|
||||
@@ -461,14 +481,14 @@ namespace net_utils
|
||||
}
|
||||
|
||||
template<class t_handler>
|
||||
bool async_call(t_handler t_callback)
|
||||
bool async_call(t_handler&& t_callback)
|
||||
{
|
||||
io_service_.post(t_callback);
|
||||
boost::asio::post(io_context_, std::forward<t_handler>(t_callback));
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Run the server's io_service loop.
|
||||
/// Run the server's io_context loop.
|
||||
bool worker_thread();
|
||||
/// Handle completion of an asynchronous accept operation.
|
||||
void handle_accept_ipv4(const boost::system::error_code& e);
|
||||
@@ -479,18 +499,18 @@ namespace net_utils
|
||||
|
||||
const std::shared_ptr<typename connection<t_protocol_handler>::shared_state> m_state;
|
||||
|
||||
/// The io_service used to perform asynchronous operations.
|
||||
/// The io_context used to perform asynchronous operations.
|
||||
struct worker
|
||||
{
|
||||
worker()
|
||||
: io_service(), work(io_service)
|
||||
: io_context(), work(io_context.get_executor())
|
||||
{}
|
||||
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::io_service::work work;
|
||||
boost::asio::io_context io_context;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work;
|
||||
};
|
||||
std::unique_ptr<worker> m_io_service_local_instance;
|
||||
boost::asio::io_service& io_service_;
|
||||
std::unique_ptr<worker> m_io_context_local_instance;
|
||||
boost::asio::io_context& io_context_;
|
||||
|
||||
/// Acceptor used to listen for incoming connections.
|
||||
boost::asio::ip::tcp::acceptor acceptor_;
|
||||
|
||||
@@ -31,11 +31,12 @@
|
||||
//
|
||||
|
||||
|
||||
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include <boost/chrono.hpp>
|
||||
#include <boost/utility/value_init.hpp>
|
||||
#include <boost/asio/bind_executor.hpp>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp> // TODO
|
||||
#include <boost/thread/condition_variable.hpp> // TODO
|
||||
@@ -145,23 +146,19 @@ namespace net_utils
|
||||
if (m_state.timers.general.wait_expire) {
|
||||
m_state.timers.general.cancel_expire = true;
|
||||
m_state.timers.general.reset_expire = true;
|
||||
ec_t ec;
|
||||
m_timers.general.expires_from_now(
|
||||
m_timers.general.expires_after(
|
||||
std::min(
|
||||
duration + (add ? m_timers.general.expires_from_now() : duration_t{}),
|
||||
duration + (add ? (m_timers.general.expiry() - std::chrono::steady_clock::now()) : duration_t{}),
|
||||
get_default_timeout()
|
||||
),
|
||||
ec
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
ec_t ec;
|
||||
m_timers.general.expires_from_now(
|
||||
m_timers.general.expires_after(
|
||||
std::min(
|
||||
duration + (add ? m_timers.general.expires_from_now() : duration_t{}),
|
||||
duration + (add ? (m_timers.general.expiry() - std::chrono::steady_clock::now()) : duration_t{}),
|
||||
get_default_timeout()
|
||||
),
|
||||
ec
|
||||
)
|
||||
);
|
||||
async_wait_timer();
|
||||
}
|
||||
@@ -202,8 +199,7 @@ namespace net_utils
|
||||
return;
|
||||
m_state.timers.general.cancel_expire = true;
|
||||
m_state.timers.general.reset_expire = false;
|
||||
ec_t ec;
|
||||
m_timers.general.cancel(ec);
|
||||
m_timers.general.cancel();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -225,7 +221,8 @@ namespace net_utils
|
||||
m_state.data.read.buffer.size()
|
||||
),
|
||||
boost::asio::transfer_exactly(epee::net_utils::get_ssl_magic_size()),
|
||||
m_strand.wrap(
|
||||
boost::asio::bind_executor(
|
||||
m_strand,
|
||||
[this, self](const ec_t &ec, size_t bytes_transferred){
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
m_state.socket.wait_read = false;
|
||||
@@ -246,7 +243,8 @@ namespace net_utils
|
||||
) {
|
||||
m_state.ssl.enabled = false;
|
||||
m_state.socket.handle_read = true;
|
||||
connection_basic::strand_.post(
|
||||
boost::asio::post(
|
||||
connection_basic::strand_,
|
||||
[this, self, bytes_transferred]{
|
||||
bool success = m_handler.handle_recv(
|
||||
reinterpret_cast<char *>(m_state.data.read.buffer.data()),
|
||||
@@ -304,7 +302,8 @@ namespace net_utils
|
||||
static_cast<shared_state&>(
|
||||
connection_basic::get_state()
|
||||
).ssl_options().configure(connection_basic::socket_, handshake);
|
||||
m_strand.post(
|
||||
boost::asio::post(
|
||||
m_strand,
|
||||
[this, self, on_handshake]{
|
||||
connection_basic::socket_.async_handshake(
|
||||
handshake,
|
||||
@@ -313,7 +312,7 @@ namespace net_utils
|
||||
m_state.ssl.forced ? 0 :
|
||||
epee::net_utils::get_ssl_magic_size()
|
||||
),
|
||||
m_strand.wrap(on_handshake)
|
||||
boost::asio::bind_executor(m_strand, on_handshake)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -328,7 +327,7 @@ namespace net_utils
|
||||
return;
|
||||
}
|
||||
auto self = connection<T>::shared_from_this();
|
||||
if (m_connection_type != e_connection_type_RPC) {
|
||||
if (speed_limit_is_enabled()) {
|
||||
auto calc_duration = []{
|
||||
CRITICAL_REGION_LOCAL(
|
||||
network_throttle_manager_t::m_lock_get_global_throttle_in
|
||||
@@ -345,8 +344,7 @@ namespace net_utils
|
||||
};
|
||||
const auto duration = calc_duration();
|
||||
if (duration > duration_t{}) {
|
||||
ec_t ec;
|
||||
m_timers.throttle.in.expires_from_now(duration, ec);
|
||||
m_timers.throttle.in.expires_after(duration);
|
||||
m_state.timers.throttle.in.wait_expire = true;
|
||||
m_timers.throttle.in.async_wait([this, self](const ec_t &ec){
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
@@ -382,7 +380,7 @@ namespace net_utils
|
||||
m_conn_context.m_max_speed_down,
|
||||
speed
|
||||
);
|
||||
{
|
||||
if (speed_limit_is_enabled()) {
|
||||
CRITICAL_REGION_LOCAL(
|
||||
network_throttle_manager_t::m_lock_get_global_throttle_in
|
||||
);
|
||||
@@ -401,7 +399,8 @@ namespace net_utils
|
||||
// writes until the connection terminates without deadlocking waiting
|
||||
// for handle_recv.
|
||||
m_state.socket.handle_read = true;
|
||||
connection_basic::strand_.post(
|
||||
boost::asio::post(
|
||||
connection_basic::strand_,
|
||||
[this, self, bytes_transferred]{
|
||||
bool success = m_handler.handle_recv(
|
||||
reinterpret_cast<char *>(m_state.data.read.buffer.data()),
|
||||
@@ -428,17 +427,18 @@ namespace net_utils
|
||||
m_state.data.read.buffer.data(),
|
||||
m_state.data.read.buffer.size()
|
||||
),
|
||||
m_strand.wrap(on_read)
|
||||
boost::asio::bind_executor(m_strand, on_read)
|
||||
);
|
||||
else
|
||||
m_strand.post(
|
||||
boost::asio::post(
|
||||
m_strand,
|
||||
[this, self, on_read]{
|
||||
connection_basic::socket_.async_read_some(
|
||||
boost::asio::buffer(
|
||||
m_state.data.read.buffer.data(),
|
||||
m_state.data.read.buffer.size()
|
||||
),
|
||||
m_strand.wrap(on_read)
|
||||
boost::asio::bind_executor(m_strand, on_read)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -454,7 +454,7 @@ namespace net_utils
|
||||
return;
|
||||
}
|
||||
auto self = connection<T>::shared_from_this();
|
||||
if (m_connection_type != e_connection_type_RPC) {
|
||||
if (speed_limit_is_enabled()) {
|
||||
auto calc_duration = [this]{
|
||||
CRITICAL_REGION_LOCAL(
|
||||
network_throttle_manager_t::m_lock_get_global_throttle_out
|
||||
@@ -473,8 +473,7 @@ namespace net_utils
|
||||
};
|
||||
const auto duration = calc_duration();
|
||||
if (duration > duration_t{}) {
|
||||
ec_t ec;
|
||||
m_timers.throttle.out.expires_from_now(duration, ec);
|
||||
m_timers.throttle.out.expires_after(duration);
|
||||
m_state.timers.throttle.out.wait_expire = true;
|
||||
m_timers.throttle.out.async_wait([this, self](const ec_t &ec){
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
@@ -498,10 +497,12 @@ namespace net_utils
|
||||
if (m_state.socket.cancel_write) {
|
||||
m_state.socket.cancel_write = false;
|
||||
m_state.data.write.queue.clear();
|
||||
m_state.data.write.total_bytes = 0;
|
||||
state_status_check();
|
||||
}
|
||||
else if (ec.value()) {
|
||||
m_state.data.write.queue.clear();
|
||||
m_state.data.write.total_bytes = 0;
|
||||
interrupt();
|
||||
}
|
||||
else {
|
||||
@@ -513,7 +514,7 @@ namespace net_utils
|
||||
m_conn_context.m_max_speed_down,
|
||||
speed
|
||||
);
|
||||
{
|
||||
if (speed_limit_is_enabled()) {
|
||||
CRITICAL_REGION_LOCAL(
|
||||
network_throttle_manager_t::m_lock_get_global_throttle_out
|
||||
);
|
||||
@@ -526,8 +527,11 @@ namespace net_utils
|
||||
|
||||
start_timer(get_default_timeout(), true);
|
||||
}
|
||||
assert(bytes_transferred == m_state.data.write.queue.back().size());
|
||||
const std::size_t byte_count = m_state.data.write.queue.back().size();
|
||||
assert(bytes_transferred == byte_count);
|
||||
m_state.data.write.queue.pop_back();
|
||||
m_state.data.write.total_bytes -=
|
||||
std::min(m_state.data.write.total_bytes, byte_count);
|
||||
m_state.condition.notify_all();
|
||||
start_write();
|
||||
}
|
||||
@@ -539,10 +543,11 @@ namespace net_utils
|
||||
m_state.data.write.queue.back().data(),
|
||||
m_state.data.write.queue.back().size()
|
||||
),
|
||||
m_strand.wrap(on_write)
|
||||
boost::asio::bind_executor(m_strand, on_write)
|
||||
);
|
||||
else
|
||||
m_strand.post(
|
||||
boost::asio::post(
|
||||
m_strand,
|
||||
[this, self, on_write]{
|
||||
boost::asio::async_write(
|
||||
connection_basic::socket_,
|
||||
@@ -550,7 +555,7 @@ namespace net_utils
|
||||
m_state.data.write.queue.back().data(),
|
||||
m_state.data.write.queue.back().size()
|
||||
),
|
||||
m_strand.wrap(on_write)
|
||||
boost::asio::bind_executor(m_strand, on_write)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -587,10 +592,11 @@ namespace net_utils
|
||||
terminate();
|
||||
}
|
||||
};
|
||||
m_strand.post(
|
||||
boost::asio::post(
|
||||
m_strand,
|
||||
[this, self, on_shutdown]{
|
||||
connection_basic::socket_.async_shutdown(
|
||||
m_strand.wrap(on_shutdown)
|
||||
boost::asio::bind_executor(m_strand, on_shutdown)
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -605,15 +611,13 @@ namespace net_utils
|
||||
wait_socket = m_state.socket.cancel_handshake = true;
|
||||
if (m_state.timers.throttle.in.wait_expire) {
|
||||
m_state.timers.throttle.in.cancel_expire = true;
|
||||
ec_t ec;
|
||||
m_timers.throttle.in.cancel(ec);
|
||||
m_timers.throttle.in.cancel();
|
||||
}
|
||||
if (m_state.socket.wait_read)
|
||||
wait_socket = m_state.socket.cancel_read = true;
|
||||
if (m_state.timers.throttle.out.wait_expire) {
|
||||
m_state.timers.throttle.out.cancel_expire = true;
|
||||
ec_t ec;
|
||||
m_timers.throttle.out.cancel(ec);
|
||||
m_timers.throttle.out.cancel();
|
||||
}
|
||||
if (m_state.socket.wait_write)
|
||||
wait_socket = m_state.socket.cancel_write = true;
|
||||
@@ -671,8 +675,9 @@ namespace net_utils
|
||||
return;
|
||||
if (m_state.timers.throttle.out.wait_expire)
|
||||
return;
|
||||
if (m_state.socket.wait_write)
|
||||
return;
|
||||
// \NOTE See on_terminating() comments
|
||||
//if (m_state.socket.wait_write)
|
||||
// return;
|
||||
if (m_state.socket.wait_shutdown)
|
||||
return;
|
||||
if (m_state.protocol.wait_init)
|
||||
@@ -730,8 +735,13 @@ namespace net_utils
|
||||
return;
|
||||
if (m_state.timers.throttle.out.wait_expire)
|
||||
return;
|
||||
if (m_state.socket.wait_write)
|
||||
return;
|
||||
// Writes cannot be canceled due to `async_write` being a "composed"
|
||||
// handler. ASIO has new cancellation routines, not available in 1.66, to
|
||||
// handle this situation. The problem is that if cancel is called after an
|
||||
// intermediate handler is queued, the op will not check the cancel flag in
|
||||
// our code, and will instead queue up another write.
|
||||
//if (m_state.socket.wait_write)
|
||||
// return;
|
||||
if (m_state.socket.wait_shutdown)
|
||||
return;
|
||||
if (m_state.protocol.wait_init)
|
||||
@@ -758,6 +768,8 @@ namespace net_utils
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
if (m_state.status != status_t::RUNNING || m_state.socket.wait_handshake)
|
||||
return false;
|
||||
if (std::numeric_limits<std::size_t>::max() - m_state.data.write.total_bytes < message.size())
|
||||
return false;
|
||||
|
||||
// Wait for the write queue to fall below the max. If it doesn't after a
|
||||
// randomized delay, drop the connection.
|
||||
@@ -775,7 +787,14 @@ namespace net_utils
|
||||
std::uniform_int_distribution<>(5000, 6000)(rng)
|
||||
);
|
||||
};
|
||||
if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT)
|
||||
|
||||
// The bytes check intentionally does not include incoming message size.
|
||||
// This allows for a soft overflow; a single http response will never fail
|
||||
// this check, but multiple responses could. Clients can avoid this case
|
||||
// by reading the entire response before making another request. P2P
|
||||
// should never hit the MAX_BYTES check (when using default values).
|
||||
if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
|
||||
m_state.data.write.total_bytes <= static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit)
|
||||
return true;
|
||||
m_state.data.write.wait_consume = true;
|
||||
bool success = m_state.condition.wait_for(
|
||||
@@ -784,14 +803,23 @@ namespace net_utils
|
||||
[this]{
|
||||
return (
|
||||
m_state.status != status_t::RUNNING ||
|
||||
m_state.data.write.queue.size() <=
|
||||
ABSTRACT_SERVER_SEND_QUE_MAX_COUNT
|
||||
(
|
||||
m_state.data.write.queue.size() <=
|
||||
ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
|
||||
m_state.data.write.total_bytes <=
|
||||
static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
m_state.data.write.wait_consume = false;
|
||||
if (!success) {
|
||||
terminate();
|
||||
// synchronize with intermediate writes on `m_strand`
|
||||
auto self = connection<T>::shared_from_this();
|
||||
boost::asio::post(m_strand, [this, self] {
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
terminate();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@@ -817,7 +845,9 @@ namespace net_utils
|
||||
) {
|
||||
if (!wait_consume())
|
||||
return false;
|
||||
const std::size_t byte_count = message.size();
|
||||
m_state.data.write.queue.emplace_front(std::move(message));
|
||||
m_state.data.write.total_bytes += byte_count;
|
||||
start_write();
|
||||
}
|
||||
else {
|
||||
@@ -827,6 +857,7 @@ namespace net_utils
|
||||
m_state.data.write.queue.emplace_front(
|
||||
message.take_slice(CHUNK_SIZE)
|
||||
);
|
||||
m_state.data.write.total_bytes += m_state.data.write.queue.front().size();
|
||||
start_write();
|
||||
}
|
||||
}
|
||||
@@ -860,7 +891,7 @@ namespace net_utils
|
||||
ipv4_network_address{
|
||||
uint32_t{
|
||||
boost::asio::detail::socket_ops::host_to_network_long(
|
||||
endpoint.address().to_v4().to_ulong()
|
||||
endpoint.address().to_v4().to_uint()
|
||||
)
|
||||
},
|
||||
endpoint.port()
|
||||
@@ -873,6 +904,13 @@ namespace net_utils
|
||||
).pfilter;
|
||||
if (filter && !filter->is_remote_host_allowed(*real_remote))
|
||||
return false;
|
||||
|
||||
auto *limit = static_cast<shared_state&>(
|
||||
connection_basic::get_state()
|
||||
).plimit;
|
||||
if (limit && limit->is_host_limit(*real_remote))
|
||||
return false;
|
||||
|
||||
ec_t ec;
|
||||
#if !defined(_WIN32) || !defined(__i686)
|
||||
connection_basic::socket_.next_layer().set_option(
|
||||
@@ -938,7 +976,8 @@ namespace net_utils
|
||||
ssl_support_t ssl_support
|
||||
):
|
||||
connection(
|
||||
std::move(socket_t{io_context}),
|
||||
io_context,
|
||||
socket_t{io_context},
|
||||
std::move(shared_state),
|
||||
connection_type,
|
||||
ssl_support
|
||||
@@ -948,15 +987,16 @@ namespace net_utils
|
||||
|
||||
template<typename T>
|
||||
connection<T>::connection(
|
||||
io_context_t &io_context,
|
||||
socket_t &&socket,
|
||||
std::shared_ptr<shared_state> shared_state,
|
||||
t_connection_type connection_type,
|
||||
ssl_support_t ssl_support
|
||||
):
|
||||
connection_basic(std::move(socket), shared_state, ssl_support),
|
||||
connection_basic(io_context, std::move(socket), shared_state, ssl_support),
|
||||
m_handler(this, *shared_state, m_conn_context),
|
||||
m_connection_type(connection_type),
|
||||
m_io_context{GET_IO_SERVICE(connection_basic::socket_)},
|
||||
m_io_context{io_context},
|
||||
m_strand{m_io_context},
|
||||
m_timers{m_io_context}
|
||||
{
|
||||
@@ -1022,7 +1062,7 @@ namespace net_utils
|
||||
template<typename T>
|
||||
bool connection<T>::speed_limit_is_enabled() const
|
||||
{
|
||||
return m_connection_type != e_connection_type_RPC;
|
||||
return m_connection_type == e_connection_type_P2P;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -1075,7 +1115,7 @@ namespace net_utils
|
||||
return false;
|
||||
auto self = connection<T>::shared_from_this();
|
||||
++m_state.protocol.wait_callback;
|
||||
connection_basic::strand_.post([this, self]{
|
||||
boost::asio::post(connection_basic::strand_, [this, self]{
|
||||
m_handler.handle_qued_callback();
|
||||
std::lock_guard<std::mutex> guard(m_state.lock);
|
||||
--m_state.protocol.wait_callback;
|
||||
@@ -1088,7 +1128,7 @@ namespace net_utils
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename connection<T>::io_context_t &connection<T>::get_io_service()
|
||||
typename connection<T>::io_context_t &connection<T>::get_io_context()
|
||||
{
|
||||
return m_io_context;
|
||||
}
|
||||
@@ -1128,10 +1168,10 @@ namespace net_utils
|
||||
template<class t_protocol_handler>
|
||||
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server( t_connection_type connection_type ) :
|
||||
m_state(std::make_shared<typename connection<t_protocol_handler>::shared_state>()),
|
||||
m_io_service_local_instance(new worker()),
|
||||
io_service_(m_io_service_local_instance->io_service),
|
||||
acceptor_(io_service_),
|
||||
acceptor_ipv6(io_service_),
|
||||
m_io_context_local_instance(new worker()),
|
||||
io_context_(m_io_context_local_instance->io_context),
|
||||
acceptor_(io_context_),
|
||||
acceptor_ipv6(io_context_),
|
||||
default_remote(),
|
||||
m_stop_signal_sent(false), m_port(0),
|
||||
m_threads_count(0),
|
||||
@@ -1145,11 +1185,11 @@ namespace net_utils
|
||||
}
|
||||
|
||||
template<class t_protocol_handler>
|
||||
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server(boost::asio::io_service& extarnal_io_service, t_connection_type connection_type) :
|
||||
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server(boost::asio::io_context& extarnal_io_context, t_connection_type connection_type) :
|
||||
m_state(std::make_shared<typename connection<t_protocol_handler>::shared_state>()),
|
||||
io_service_(extarnal_io_service),
|
||||
acceptor_(io_service_),
|
||||
acceptor_ipv6(io_service_),
|
||||
io_context_(extarnal_io_context),
|
||||
acceptor_(io_context_),
|
||||
acceptor_ipv6(io_context_),
|
||||
default_remote(),
|
||||
m_stop_signal_sent(false), m_port(0),
|
||||
m_threads_count(0),
|
||||
@@ -1196,24 +1236,27 @@ namespace net_utils
|
||||
|
||||
std::string ipv4_failed = "";
|
||||
std::string ipv6_failed = "";
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_context_);
|
||||
|
||||
try
|
||||
{
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_.open(endpoint.protocol());
|
||||
const auto results = resolver.resolve(
|
||||
address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::canonical_name
|
||||
);
|
||||
acceptor_.open(results.begin()->endpoint().protocol());
|
||||
#if !defined(_WIN32)
|
||||
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
#endif
|
||||
acceptor_.bind(endpoint);
|
||||
acceptor_.bind(*results.begin());
|
||||
acceptor_.listen();
|
||||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
|
||||
m_port = binded_endpoint.port();
|
||||
MDEBUG("start accept (IPv4)");
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
new_connection_.reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
acceptor_.async_accept(new_connection_->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4, this,
|
||||
boost::asio::placeholders::error));
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -1234,23 +1277,25 @@ namespace net_utils
|
||||
try
|
||||
{
|
||||
if (port_ipv6 == 0) port_ipv6 = port; // default arg means bind to same port as ipv4
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
|
||||
acceptor_ipv6.open(endpoint.protocol());
|
||||
|
||||
const auto results = resolver.resolve(
|
||||
address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::canonical_name
|
||||
);
|
||||
|
||||
acceptor_ipv6.open(results.begin()->endpoint().protocol());
|
||||
#if !defined(_WIN32)
|
||||
acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
#endif
|
||||
acceptor_ipv6.set_option(boost::asio::ip::v6_only(true));
|
||||
acceptor_ipv6.bind(endpoint);
|
||||
acceptor_ipv6.bind(*results.begin());
|
||||
acceptor_ipv6.listen();
|
||||
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_ipv6.local_endpoint();
|
||||
m_port_ipv6 = binded_endpoint.port();
|
||||
MDEBUG("start accept (IPv6)");
|
||||
new_connection_ipv6.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
new_connection_ipv6.reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, m_state->ssl_options().support));
|
||||
acceptor_ipv6.async_accept(new_connection_ipv6->socket(),
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6, this,
|
||||
boost::asio::placeholders::error));
|
||||
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -1314,7 +1359,7 @@ namespace net_utils
|
||||
{
|
||||
try
|
||||
{
|
||||
io_service_.run();
|
||||
io_context_.run();
|
||||
return true;
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
@@ -1349,6 +1394,20 @@ namespace net_utils
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::set_connection_limit(i_connection_limit* plimit)
|
||||
{
|
||||
assert(m_state != nullptr); // always set in constructor
|
||||
m_state->plimit = plimit;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
void boosted_tcp_server<t_protocol_handler>::set_response_soft_limit(const std::size_t limit)
|
||||
{
|
||||
assert(m_state != nullptr); // always set in constructor
|
||||
m_state->response_soft_limit = limit;
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::run_server(size_t threads_count, bool wait, const boost::thread::attributes& attrs)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
@@ -1358,7 +1417,7 @@ namespace net_utils
|
||||
while(!m_stop_signal_sent)
|
||||
{
|
||||
|
||||
// Create a pool of threads to run all of the io_services.
|
||||
// Create a pool of threads to run all of the io_contexts.
|
||||
CRITICAL_REGION_BEGIN(m_threads_lock);
|
||||
for (std::size_t i = 0; i < threads_count; ++i)
|
||||
{
|
||||
@@ -1450,7 +1509,7 @@ namespace net_utils
|
||||
}
|
||||
connections_.clear();
|
||||
connections_mutex.unlock();
|
||||
io_service_.stop();
|
||||
io_context_.stop();
|
||||
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::send_stop_signal()", void());
|
||||
}
|
||||
//---------------------------------------------------------------------------------
|
||||
@@ -1497,7 +1556,7 @@ namespace net_utils
|
||||
(*current_new_connection)->setRpcStation(); // hopefully this is not needed actually
|
||||
}
|
||||
connection_ptr conn(std::move((*current_new_connection)));
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support()));
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, conn->get_ssl_support()));
|
||||
current_acceptor->async_accept((*current_new_connection)->socket(),
|
||||
boost::bind(accept_function_pointer, this,
|
||||
boost::asio::placeholders::error));
|
||||
@@ -1532,7 +1591,7 @@ namespace net_utils
|
||||
assert(m_state != nullptr); // always set in constructor
|
||||
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
|
||||
misc_utils::sleep_no_w(100);
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, (*current_new_connection)->get_ssl_support()));
|
||||
(*current_new_connection).reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, (*current_new_connection)->get_ssl_support()));
|
||||
current_acceptor->async_accept((*current_new_connection)->socket(),
|
||||
boost::bind(accept_function_pointer, this,
|
||||
boost::asio::placeholders::error));
|
||||
@@ -1541,9 +1600,9 @@ namespace net_utils
|
||||
template<class t_protocol_handler>
|
||||
bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
if(std::addressof(get_io_service()) == std::addressof(GET_IO_SERVICE(sock)))
|
||||
if(std::addressof(get_io_context()) == std::addressof(sock.get_executor().context()))
|
||||
{
|
||||
connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type, ssl_support));
|
||||
connection_ptr conn(new connection<t_protocol_handler>(io_context_, std::move(sock), m_state, m_connection_type, ssl_support));
|
||||
if(conn->start(false, 1 < m_threads_count, std::move(real_remote)))
|
||||
{
|
||||
conn->get_context(out);
|
||||
@@ -1553,7 +1612,7 @@ namespace net_utils
|
||||
}
|
||||
else
|
||||
{
|
||||
MWARNING(out << " was not added, socket/io_service mismatch");
|
||||
MWARNING(out << " was not added, socket/io_context mismatch");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1566,7 +1625,7 @@ namespace net_utils
|
||||
sock_.open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(bind_ip.c_str()), 0);
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip), 0);
|
||||
boost::system::error_code ec;
|
||||
sock_.bind(local_endpoint, ec);
|
||||
if (ec)
|
||||
@@ -1661,7 +1720,7 @@ namespace net_utils
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support) );
|
||||
connections_mutex.lock();
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
@@ -1671,14 +1730,16 @@ namespace net_utils
|
||||
|
||||
bool try_ipv6 = false;
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver resolver(io_context_);
|
||||
boost::asio::ip::tcp::resolver::results_type results{};
|
||||
boost::system::error_code resolve_error;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
|
||||
try
|
||||
{
|
||||
//resolving ipv4 address as ipv6 throws, catch here and move on
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
@@ -1696,8 +1757,7 @@ namespace net_utils
|
||||
|
||||
std::string bind_ip_to_use;
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
if(results.empty())
|
||||
{
|
||||
if (!m_use_ipv6)
|
||||
{
|
||||
@@ -1717,11 +1777,11 @@ namespace net_utils
|
||||
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
|
||||
iterator = resolver.resolve(query6, resolve_error);
|
||||
|
||||
if(iterator == end)
|
||||
if(results.empty())
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
@@ -1741,6 +1801,8 @@ namespace net_utils
|
||||
|
||||
}
|
||||
|
||||
const auto iterator = results.begin();
|
||||
|
||||
MDEBUG("Trying to connect to " << adr << ":" << port << ", bind_ip = " << bind_ip_to_use);
|
||||
|
||||
//boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
|
||||
@@ -1767,7 +1829,6 @@ namespace net_utils
|
||||
if (r)
|
||||
{
|
||||
new_connection_l->get_context(conn_context);
|
||||
//new_connection_l.reset(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_pfilter));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1786,7 +1847,7 @@ namespace net_utils
|
||||
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
|
||||
{
|
||||
TRY_ENTRY();
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
|
||||
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support) );
|
||||
connections_mutex.lock();
|
||||
connections_.insert(new_connection_l);
|
||||
MDEBUG("connections_ size now " << connections_.size());
|
||||
@@ -1796,14 +1857,16 @@ namespace net_utils
|
||||
|
||||
bool try_ipv6 = false;
|
||||
|
||||
boost::asio::ip::tcp::resolver resolver(io_service_);
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver resolver(io_context_);
|
||||
boost::asio::ip::tcp::resolver::results_type results{};
|
||||
boost::system::error_code resolve_error;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
|
||||
try
|
||||
{
|
||||
//resolving ipv4 address as ipv6 throws, catch here and move on
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
}
|
||||
catch (const boost::system::system_error& e)
|
||||
{
|
||||
@@ -1819,8 +1882,7 @@ namespace net_utils
|
||||
throw;
|
||||
}
|
||||
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
if(iterator == end)
|
||||
if(results.empty())
|
||||
{
|
||||
if (!try_ipv6)
|
||||
{
|
||||
@@ -1835,24 +1897,23 @@ namespace net_utils
|
||||
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
|
||||
iterator = resolver.resolve(query6, resolve_error);
|
||||
|
||||
if(iterator == end)
|
||||
if(results.empty())
|
||||
{
|
||||
_erro("Failed to resolve " << adr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
|
||||
boost::asio::ip::tcp::endpoint remote_endpoint(*results.begin());
|
||||
|
||||
sock_.open(remote_endpoint.protocol());
|
||||
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
|
||||
{
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(bind_ip.c_str()), 0);
|
||||
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip.c_str()), 0);
|
||||
boost::system::error_code ec;
|
||||
sock_.bind(local_endpoint, ec);
|
||||
if (ec)
|
||||
@@ -1864,7 +1925,7 @@ namespace net_utils
|
||||
}
|
||||
}
|
||||
|
||||
boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_service_));
|
||||
boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_context_));
|
||||
//start deadline
|
||||
sh_deadline->expires_from_now(boost::posix_time::milliseconds(conn_timeout));
|
||||
sh_deadline->async_wait([=](const boost::system::error_code& error)
|
||||
|
||||
@@ -112,21 +112,20 @@ class connection_basic { // not-templated base class for rapid developmet of som
|
||||
std::deque<byte_slice> m_send_que;
|
||||
volatile bool m_is_multithreaded;
|
||||
/// Strand to ensure the connection's handlers are not called concurrently.
|
||||
boost::asio::io_service::strand strand_;
|
||||
boost::asio::io_context::strand strand_;
|
||||
/// Socket for the connection.
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
|
||||
ssl_support_t m_ssl_support;
|
||||
|
||||
public:
|
||||
// first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator
|
||||
connection_basic(boost::asio::ip::tcp::socket&& socket, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
|
||||
connection_basic(boost::asio::io_service &io_service, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
|
||||
connection_basic(boost::asio::io_context &context, boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
|
||||
connection_basic(boost::asio::io_context &context, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
|
||||
|
||||
virtual ~connection_basic() noexcept(false);
|
||||
|
||||
//! \return `shared_state` object passed in construction (ptr never changes).
|
||||
connection_basic_shared_state& get_state() noexcept { return *m_state; /* verified in constructor */ }
|
||||
connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number, ssl_support_t ssl);
|
||||
|
||||
boost::asio::ip::tcp::socket& socket() { return socket_.next_layer(); }
|
||||
ssl_support_t get_ssl_support() const { return m_ssl_support; }
|
||||
@@ -135,7 +134,7 @@ class connection_basic { // not-templated base class for rapid developmet of som
|
||||
bool handshake(boost::asio::ssl::stream_base::handshake_type type, boost::asio::const_buffer buffer = {})
|
||||
{
|
||||
//m_state != nullptr verified in constructor
|
||||
return m_state->ssl_options().handshake(socket_, type, buffer);
|
||||
return m_state->ssl_options().handshake(strand_.context(), socket_, type, buffer);
|
||||
}
|
||||
|
||||
template<typename MutableBufferSequence, typename ReadHandler>
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include "net_utils_base.h"
|
||||
#include "http_auth.h"
|
||||
#include "http_base.h"
|
||||
@@ -54,8 +55,13 @@ namespace net_utils
|
||||
{
|
||||
std::string m_folder;
|
||||
std::vector<std::string> m_access_control_origins;
|
||||
std::unordered_map<std::string, std::size_t> m_connections;
|
||||
boost::optional<login> m_user;
|
||||
size_t m_max_content_length{std::numeric_limits<size_t>::max()};
|
||||
std::size_t m_connection_count{0};
|
||||
std::size_t m_max_public_ip_connections{3};
|
||||
std::size_t m_max_private_ip_connections{25};
|
||||
std::size_t m_max_connections{100};
|
||||
critical_section m_lock;
|
||||
};
|
||||
|
||||
@@ -70,7 +76,7 @@ namespace net_utils
|
||||
typedef http_server_config config_type;
|
||||
|
||||
simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context);
|
||||
virtual ~simple_http_connection_handler(){}
|
||||
virtual ~simple_http_connection_handler();
|
||||
|
||||
bool release_protocol()
|
||||
{
|
||||
@@ -86,10 +92,7 @@ namespace net_utils
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool after_init_connection()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
bool after_init_connection();
|
||||
virtual bool handle_recv(const void* ptr, size_t cb);
|
||||
virtual bool handle_request(const http::http_request_info& query_info, http_response_info& response);
|
||||
|
||||
@@ -146,6 +149,7 @@ namespace net_utils
|
||||
protected:
|
||||
i_service_endpoint* m_psnd_hndlr;
|
||||
t_connection_context& m_conn_context;
|
||||
bool m_initialized;
|
||||
};
|
||||
|
||||
template<class t_connection_context>
|
||||
@@ -212,10 +216,6 @@ namespace net_utils
|
||||
}
|
||||
void handle_qued_callback()
|
||||
{}
|
||||
bool after_init_connection()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
//simple_http_connection_handler::config_type m_stub_config;
|
||||
|
||||
@@ -208,11 +208,46 @@ namespace net_utils
|
||||
m_newlines(0),
|
||||
m_bytes_read(0),
|
||||
m_psnd_hndlr(psnd_hndlr),
|
||||
m_conn_context(conn_context)
|
||||
m_conn_context(conn_context),
|
||||
m_initialized(false)
|
||||
{
|
||||
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
simple_http_connection_handler<t_connection_context>::~simple_http_connection_handler()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_initialized)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_config.m_lock);
|
||||
if (m_config.m_connection_count)
|
||||
--m_config.m_connection_count;
|
||||
auto elem = m_config.m_connections.find(m_conn_context.m_remote_address.host_str());
|
||||
if (elem != m_config.m_connections.end())
|
||||
{
|
||||
if (elem->second == 1 || elem->second == 0)
|
||||
m_config.m_connections.erase(elem);
|
||||
else
|
||||
--(elem->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::after_init_connection()
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_config.m_lock);
|
||||
++m_config.m_connections[m_conn_context.m_remote_address.host_str()];
|
||||
++m_config.m_connection_count;
|
||||
m_initialized = true;
|
||||
return true;
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------
|
||||
template<class t_connection_context>
|
||||
bool simple_http_connection_handler<t_connection_context>::set_ready_state()
|
||||
{
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
else if((query_info.m_URI == s_pattern) && (cond)) \
|
||||
{ \
|
||||
handled = true; \
|
||||
uint64_t ticks = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::request> req; \
|
||||
bool parse_res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
|
||||
if (!parse_res) \
|
||||
@@ -107,7 +107,7 @@
|
||||
else if(query_info.m_URI == s_pattern) \
|
||||
{ \
|
||||
handled = true; \
|
||||
uint64_t ticks = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::request> req; \
|
||||
bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), epee::strspan<uint8_t>(query_info.m_body)); \
|
||||
if (!parse_res) \
|
||||
@@ -117,7 +117,7 @@
|
||||
response_info.m_response_comment = "Bad request"; \
|
||||
return true; \
|
||||
} \
|
||||
uint64_t ticks1 = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
|
||||
boost::value_initialized<command_type::response> resp;\
|
||||
MINFO(m_conn_context << "calling " << s_pattern); \
|
||||
bool res = false; \
|
||||
@@ -129,7 +129,7 @@
|
||||
response_info.m_response_comment = "Internal Server Error"; \
|
||||
return true; \
|
||||
} \
|
||||
uint64_t ticks2 = misc_utils::get_tick_count(); \
|
||||
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
|
||||
epee::byte_slice buffer; \
|
||||
epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), buffer, 64 * 1024); \
|
||||
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
|
||||
@@ -171,6 +171,13 @@
|
||||
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \
|
||||
return true; \
|
||||
} \
|
||||
epee::serialization::storage_entry params_; \
|
||||
params_ = epee::serialization::storage_entry(epee::serialization::section()); \
|
||||
if(!ps.get_value("params", params_, nullptr)) \
|
||||
{ \
|
||||
epee::serialization::section params_section; \
|
||||
ps.set_value("params", std::move(params_section), nullptr); \
|
||||
} \
|
||||
if(false) return true; //just a stub to have "else if"
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind/bind.hpp>
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
#include "net/abstract_tcp_server2.h"
|
||||
#include "http_protocol_handler.h"
|
||||
#include "net/http_server_handlers_map2.h"
|
||||
@@ -44,7 +45,8 @@ namespace epee
|
||||
{
|
||||
|
||||
template<class t_child_class, class t_connection_context = epee::net_utils::connection_context_base>
|
||||
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>
|
||||
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>,
|
||||
net_utils::i_connection_limit
|
||||
{
|
||||
|
||||
public:
|
||||
@@ -52,7 +54,7 @@ namespace epee
|
||||
: m_net_server(epee::net_utils::e_connection_type_RPC)
|
||||
{}
|
||||
|
||||
explicit http_server_impl_base(boost::asio::io_service& external_io_service)
|
||||
explicit http_server_impl_base(boost::asio::io_context& external_io_service)
|
||||
: m_net_server(external_io_service)
|
||||
{}
|
||||
|
||||
@@ -60,8 +62,16 @@ namespace epee
|
||||
const std::string& bind_ipv6_address = "::", bool use_ipv6 = false, bool require_ipv4 = true,
|
||||
std::vector<std::string> access_control_origins = std::vector<std::string>(),
|
||||
boost::optional<net_utils::http::login> user = boost::none,
|
||||
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect,
|
||||
const std::size_t max_public_ip_connections = DEFAULT_RPC_MAX_CONNECTIONS_PER_PUBLIC_IP,
|
||||
const std::size_t max_private_ip_connections = DEFAULT_RPC_MAX_CONNECTIONS_PER_PRIVATE_IP,
|
||||
const std::size_t max_connections = DEFAULT_RPC_MAX_CONNECTIONS,
|
||||
const std::size_t response_soft_limit = DEFAULT_RPC_SOFT_LIMIT_SIZE)
|
||||
{
|
||||
if (max_connections < max_public_ip_connections)
|
||||
throw std::invalid_argument{"Max public IP connections cannot be more than max connections"};
|
||||
if (max_connections < max_private_ip_connections)
|
||||
throw std::invalid_argument{"Max private IP connections cannot be more than max connections"};
|
||||
|
||||
//set self as callback handler
|
||||
m_net_server.get_config_object().m_phandler = static_cast<t_child_class*>(this);
|
||||
@@ -75,6 +85,11 @@ namespace epee
|
||||
m_net_server.get_config_object().m_access_control_origins = std::move(access_control_origins);
|
||||
|
||||
m_net_server.get_config_object().m_user = std::move(user);
|
||||
m_net_server.get_config_object().m_max_public_ip_connections = max_public_ip_connections;
|
||||
m_net_server.get_config_object().m_max_private_ip_connections = max_private_ip_connections;
|
||||
m_net_server.get_config_object().m_max_connections = max_connections;
|
||||
m_net_server.set_response_soft_limit(response_soft_limit);
|
||||
m_net_server.set_connection_limit(this);
|
||||
|
||||
MGINFO("Binding on " << bind_ip << " (IPv4):" << bind_port);
|
||||
if (use_ipv6)
|
||||
@@ -131,6 +146,26 @@ namespace epee
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool is_host_limit(const net_utils::network_address& na) override final
|
||||
{
|
||||
auto& config = m_net_server.get_config_object();
|
||||
CRITICAL_REGION_LOCAL(config.m_lock);
|
||||
if (config.m_max_connections <= config.m_connection_count)
|
||||
return true;
|
||||
|
||||
const bool is_private = na.is_loopback() || na.is_local();
|
||||
const auto elem = config.m_connections.find(na.host_str());
|
||||
if (elem != config.m_connections.end())
|
||||
{
|
||||
if (is_private)
|
||||
return config.m_max_private_ip_connections <= elem->second;
|
||||
else
|
||||
return config.m_max_public_ip_connections <= elem->second;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
net_utils::boosted_tcp_server<net_utils::http::http_custom_handler<t_connection_context> > m_net_server;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ public:
|
||||
struct anvoke_handler: invoke_response_handler_base
|
||||
{
|
||||
anvoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command)
|
||||
:m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_service()), m_timer_started(false),
|
||||
:m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_context()), m_timer_started(false),
|
||||
m_cancel_timer_called(false), m_timer_cancelled(false), m_command(command)
|
||||
{
|
||||
if(m_con.start_outer_call())
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/read.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
@@ -158,11 +158,11 @@ namespace net_utils
|
||||
inline
|
||||
try_connect_result_t try_connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout)
|
||||
{
|
||||
m_deadline.expires_from_now(timeout);
|
||||
m_deadline.expires_after(timeout);
|
||||
boost::unique_future<boost::asio::ip::tcp::socket> connection = m_connector(addr, port, m_deadline);
|
||||
for (;;)
|
||||
{
|
||||
m_io_service.reset();
|
||||
m_io_service.restart();
|
||||
m_io_service.run_one();
|
||||
|
||||
if (connection.is_ready())
|
||||
@@ -178,7 +178,7 @@ namespace net_utils
|
||||
// SSL Options
|
||||
if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
if (!m_ssl_options.handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, {}, addr, timeout))
|
||||
if (!m_ssl_options.handshake(m_io_service, *m_ssl_socket, boost::asio::ssl::stream_base::client, {}, addr, timeout))
|
||||
{
|
||||
if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
|
||||
{
|
||||
@@ -285,7 +285,7 @@ namespace net_utils
|
||||
|
||||
try
|
||||
{
|
||||
m_deadline.expires_from_now(timeout);
|
||||
m_deadline.expires_after(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -303,7 +303,7 @@ namespace net_utils
|
||||
// Block until the asynchronous operation has completed.
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.reset();
|
||||
m_io_service.restart();
|
||||
m_io_service.run_one();
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ namespace net_utils
|
||||
// Set a deadline for the asynchronous operation. Since this function uses
|
||||
// a composed operation (async_read_until), the deadline applies to the
|
||||
// entire operation, rather than individual reads from the socket.
|
||||
m_deadline.expires_from_now(timeout);
|
||||
m_deadline.expires_after(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -436,7 +436,7 @@ namespace net_utils
|
||||
// Block until the asynchronous operation has completed.
|
||||
while (ec == boost::asio::error::would_block && !m_shutdowned)
|
||||
{
|
||||
m_io_service.reset();
|
||||
m_io_service.restart();
|
||||
m_io_service.run_one();
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ namespace net_utils
|
||||
// Set a deadline for the asynchronous operation. Since this function uses
|
||||
// a composed operation (async_read_until), the deadline applies to the
|
||||
// entire operation, rather than individual reads from the socket.
|
||||
m_deadline.expires_from_now(timeout);
|
||||
m_deadline.expires_after(timeout);
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
@@ -580,7 +580,7 @@ namespace net_utils
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service()
|
||||
boost::asio::io_context& get_io_service()
|
||||
{
|
||||
return m_io_service;
|
||||
}
|
||||
@@ -607,7 +607,7 @@ namespace net_utils
|
||||
// Check whether the deadline has passed. We compare the deadline against
|
||||
// the current time since a new asynchronous operation may have moved the
|
||||
// deadline before this actor had a chance to run.
|
||||
if (m_deadline.expires_at() <= std::chrono::steady_clock::now())
|
||||
if (m_deadline.expiry() <= std::chrono::steady_clock::now())
|
||||
{
|
||||
// The deadline has passed. The socket is closed so that any outstanding
|
||||
// asynchronous operations are cancelled. This allows the blocked
|
||||
@@ -628,11 +628,11 @@ namespace net_utils
|
||||
void shutdown_ssl() {
|
||||
// ssl socket shutdown blocks if server doesn't respond. We close after 2 secs
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
m_deadline.expires_from_now(std::chrono::milliseconds(2000));
|
||||
m_deadline.expires_after(std::chrono::milliseconds(2000));
|
||||
m_ssl_socket->async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
|
||||
while (ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.reset();
|
||||
m_io_service.restart();
|
||||
m_io_service.run_one();
|
||||
}
|
||||
// Ignore "short read" error
|
||||
@@ -676,7 +676,7 @@ namespace net_utils
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service m_io_service;
|
||||
boost::asio::io_context m_io_service;
|
||||
boost::asio::ssl::context m_ctx;
|
||||
std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket;
|
||||
std::function<connect_func> m_connector;
|
||||
@@ -688,119 +688,6 @@ namespace net_utils
|
||||
std::atomic<uint64_t> m_bytes_sent;
|
||||
std::atomic<uint64_t> m_bytes_received;
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class async_blocked_mode_client: public blocked_mode_client
|
||||
{
|
||||
public:
|
||||
async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service)
|
||||
{
|
||||
|
||||
// No deadline is required until the first socket operation is started. We
|
||||
// set the deadline to positive infinity so that the actor takes no action
|
||||
// until a specific deadline is set.
|
||||
m_send_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
|
||||
// Start the persistent actor that checks for deadline expiry.
|
||||
check_send_deadline();
|
||||
}
|
||||
~async_blocked_mode_client()
|
||||
{
|
||||
m_send_deadline.cancel();
|
||||
}
|
||||
|
||||
bool shutdown()
|
||||
{
|
||||
blocked_mode_client::shutdown();
|
||||
m_send_deadline.cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline
|
||||
bool send(const void* data, size_t sz)
|
||||
{
|
||||
try
|
||||
{
|
||||
/*
|
||||
m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
|
||||
|
||||
// Set up the variable that receives the result of the asynchronous
|
||||
// operation. The error code is set to would_block to signal that the
|
||||
// operation is incomplete. Asio guarantees that its asynchronous
|
||||
// operations will never fail with would_block, so any other value in
|
||||
// ec indicates completion.
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
|
||||
// Start the asynchronous operation itself. The boost::lambda function
|
||||
// object is used as a callback and will update the ec variable when the
|
||||
// operation completes. The blocking_udp_client.cpp example shows how you
|
||||
// can use boost::bind rather than boost::lambda.
|
||||
boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
while(ec == boost::asio::error::would_block)
|
||||
{
|
||||
m_io_service.run_one();
|
||||
}*/
|
||||
|
||||
boost::system::error_code ec;
|
||||
|
||||
size_t writen = write(data, sz, ec);
|
||||
|
||||
if (!writen || ec)
|
||||
{
|
||||
LOG_PRINT_L3("Problems at write: " << ec.message());
|
||||
return false;
|
||||
}else
|
||||
{
|
||||
m_send_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
}
|
||||
}
|
||||
|
||||
catch(const boost::system::system_error& er)
|
||||
{
|
||||
LOG_ERROR("Some problems at connect, message: " << er.what());
|
||||
return false;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
LOG_ERROR("Some fatal problems.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
boost::asio::deadline_timer m_send_deadline;
|
||||
|
||||
void check_send_deadline()
|
||||
{
|
||||
// Check whether the deadline has passed. We compare the deadline against
|
||||
// the current time since a new asynchronous operation may have moved the
|
||||
// deadline before this actor had a chance to run.
|
||||
if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now())
|
||||
{
|
||||
// The deadline has passed. The socket is closed so that any outstanding
|
||||
// asynchronous operations are cancelled. This allows the blocked
|
||||
// connect(), read_line() or write_line() functions to return.
|
||||
LOG_PRINT_L3("Timed out socket");
|
||||
m_ssl_socket->next_layer().close();
|
||||
|
||||
// There is no longer an active deadline. The expiry is set to positive
|
||||
// infinity so that the actor takes no action until a new deadline is set.
|
||||
m_send_deadline.expires_at(boost::posix_time::pos_infin);
|
||||
}
|
||||
|
||||
// Put the actor back to sleep.
|
||||
m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@@ -125,6 +126,7 @@ namespace net_utils
|
||||
\note It is strongly encouraged that clients using `system_ca`
|
||||
verification provide a non-empty `host` for rfc2818 verification.
|
||||
|
||||
\param io_context associated with `socket`.
|
||||
\param socket Used in SSL handshake and verification
|
||||
\param type Client or server
|
||||
\param host This parameter is only used when
|
||||
@@ -136,6 +138,7 @@ namespace net_utils
|
||||
\return True if the SSL handshake completes with peer verification
|
||||
settings. */
|
||||
bool handshake(
|
||||
boost::asio::io_context& io_context,
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket,
|
||||
boost::asio::ssl::stream_base::handshake_type type,
|
||||
boost::asio::const_buffer buffer = {},
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#define _NET_UTILS_BASE_H_
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/address_v6.hpp>
|
||||
#include <typeinfo>
|
||||
#include <type_traits>
|
||||
@@ -47,10 +47,12 @@
|
||||
#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(((uint32_t)a4)<<24))
|
||||
#endif
|
||||
|
||||
/* Use the below function carefully. The executor and io_context are slightly
|
||||
different concepts. */
|
||||
#if BOOST_VERSION >= 107000
|
||||
#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context())
|
||||
#define MONERO_GET_EXECUTOR(type) type . get_executor()
|
||||
#else
|
||||
#define GET_IO_SERVICE(s) ((s).get_io_service())
|
||||
#define MONERO_GET_EXECUTOR(type) type . get_io_context()
|
||||
#endif
|
||||
|
||||
namespace net
|
||||
@@ -443,7 +445,7 @@ namespace net_utils
|
||||
virtual bool send_done()=0;
|
||||
virtual bool call_run_once_service_io()=0;
|
||||
virtual bool request_callback()=0;
|
||||
virtual boost::asio::io_service& get_io_service()=0;
|
||||
virtual boost::asio::io_context& get_io_context()=0;
|
||||
//protect from deletion connection object(with protocol instance) during external call "invoke"
|
||||
virtual bool add_ref()=0;
|
||||
virtual bool release()=0;
|
||||
|
||||
@@ -46,13 +46,13 @@ namespace net_utils
|
||||
|
||||
|
||||
class network_throttle : public i_network_throttle {
|
||||
private:
|
||||
public:
|
||||
struct packet_info {
|
||||
size_t m_size; // octets sent. Summary for given small-window (e.g. for all packaged in 1 second)
|
||||
packet_info();
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
network_speed_bps m_target_speed;
|
||||
size_t m_network_add_cost; // estimated add cost of headers
|
||||
size_t m_network_minimal_segment; // estimated minimal cost of sending 1 byte to round up to
|
||||
|
||||
@@ -98,16 +98,18 @@ public: \
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \
|
||||
epee::serialization::selector<is_store>::serialize_t_val_as_blob(this_ref.varialble, stg, hparent_section, val_name);
|
||||
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, val_name) \
|
||||
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(variable, val_name) \
|
||||
static_assert(std::is_trivially_copyable<decltype(this_ref.variable)>(), "t_type must be a trivially copyable type."); \
|
||||
static_assert(std::is_standard_layout<decltype(this_ref.variable)>(), "t_type must be a standard layout type."); \
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(variable, val_name)
|
||||
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, val_name, default_value) \
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(variable, val_name, default_value) \
|
||||
do { \
|
||||
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
|
||||
bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name); \
|
||||
static_assert(std::is_trivially_copyable<decltype(this_ref.variable)>(), "t_type must be a trivially copyable type."); \
|
||||
static_assert(std::is_standard_layout<decltype(this_ref.variable)>(), "t_type must be a standard layout type."); \
|
||||
bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(variable, val_name) \
|
||||
if (!ret) \
|
||||
epee::serialize_default(this_ref.varialble, default_value); \
|
||||
epee::serialize_default(this_ref.variable, default_value); \
|
||||
} while(0);
|
||||
|
||||
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \
|
||||
@@ -118,7 +120,7 @@ public: \
|
||||
#define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(varialble, def) KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, #varialble, def)
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check
|
||||
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_trivially_copyable and is_standard_layout compile time check
|
||||
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble)
|
||||
#define KV_SERIALIZE_OPT(variable,default_value) KV_SERIALIZE_OPT_N(variable, #variable, default_value)
|
||||
|
||||
|
||||
+13
-10
@@ -133,17 +133,14 @@ namespace epee
|
||||
return {src.data(), src.size()};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr bool has_padding() noexcept
|
||||
{
|
||||
return !std::is_standard_layout<T>() || alignof(T) != 1;
|
||||
}
|
||||
|
||||
//! \return Cast data from `src` as `span<const std::uint8_t>`.
|
||||
template<typename T>
|
||||
span<const std::uint8_t> to_byte_span(const span<const T> src) noexcept
|
||||
{
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
static_assert(!std::is_empty<T>(), "empty value types will not work -> sizeof == 1");
|
||||
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
|
||||
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
|
||||
static_assert(alignof(T) == 1, "type may have padding");
|
||||
return {reinterpret_cast<const std::uint8_t*>(src.data()), src.size_bytes()};
|
||||
}
|
||||
|
||||
@@ -153,7 +150,9 @@ namespace epee
|
||||
{
|
||||
using value_type = typename T::value_type;
|
||||
static_assert(!std::is_empty<value_type>(), "empty value types will not work -> sizeof == 1");
|
||||
static_assert(!has_padding<value_type>(), "source value type may have padding");
|
||||
static_assert(std::is_standard_layout<value_type>(), "value type must have standard layout");
|
||||
static_assert(std::is_trivially_copyable<value_type>(), "value type must be trivially copyable");
|
||||
static_assert(alignof(value_type) == 1, "value type may have padding");
|
||||
return {reinterpret_cast<std::uint8_t*>(src.data()), src.size() * sizeof(value_type)};
|
||||
}
|
||||
|
||||
@@ -162,7 +161,9 @@ namespace epee
|
||||
span<const std::uint8_t> as_byte_span(const T& src) noexcept
|
||||
{
|
||||
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
|
||||
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
|
||||
static_assert(alignof(T) == 1, "type may have padding");
|
||||
return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)};
|
||||
}
|
||||
|
||||
@@ -171,7 +172,9 @@ namespace epee
|
||||
span<std::uint8_t> as_mut_byte_span(T& src) noexcept
|
||||
{
|
||||
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
|
||||
static_assert(!has_padding<T>(), "source type may have padding");
|
||||
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
|
||||
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
|
||||
static_assert(alignof(T) == 1, "type may have padding");
|
||||
return {reinterpret_cast<std::uint8_t*>(std::addressof(src)), sizeof(T)};
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/numeric/conversion/bounds.hpp>
|
||||
#include <typeinfo>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "mlocker.h"
|
||||
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
@@ -69,23 +70,17 @@ namespace string_tools
|
||||
#ifdef _WIN32
|
||||
std::string get_current_module_path();
|
||||
#endif
|
||||
bool set_module_name_and_folder(const std::string& path_to_process_);
|
||||
bool trim_left(std::string& str);
|
||||
bool trim_right(std::string& str);
|
||||
void set_module_name_and_folder(const std::string& path_to_process_);
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string& trim(std::string& str)
|
||||
{
|
||||
trim_left(str);
|
||||
trim_right(str);
|
||||
boost::trim(str);
|
||||
return str;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline std::string trim(const std::string& str_)
|
||||
inline std::string trim(const std::string& str)
|
||||
{
|
||||
std::string str = str_;
|
||||
trim_left(str);
|
||||
trim_right(str);
|
||||
return str;
|
||||
return boost::trim_copy(str);
|
||||
}
|
||||
std::string pad_string(std::string s, size_t n, char c = ' ', bool prepend = false);
|
||||
|
||||
@@ -94,6 +89,7 @@ namespace string_tools
|
||||
std::string pod_to_hex(const t_pod_type& s)
|
||||
{
|
||||
static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type");
|
||||
static_assert(alignof(t_pod_type) == 1, "type may have padding");
|
||||
return to_hex::string(as_byte_span(s));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
@@ -101,6 +97,8 @@ namespace string_tools
|
||||
bool hex_to_pod(const boost::string_ref hex_str, t_pod_type& s)
|
||||
{
|
||||
static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type");
|
||||
static_assert(alignof(t_pod_type) == 1, "type may have padding");
|
||||
static_assert(std::is_trivially_copyable<t_pod_type>(), "type must be trivially copyable");
|
||||
return from_hex::to_buffer(as_mut_byte_span(s), hex_str);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -135,6 +135,13 @@ namespace http
|
||||
http::url_content parsed{};
|
||||
const bool r = parse_url(address, parsed);
|
||||
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
|
||||
if (parsed.port == 0)
|
||||
{
|
||||
if (parsed.schema == "http")
|
||||
parsed.port = 80;
|
||||
else if (parsed.schema == "https")
|
||||
parsed.port = 443;
|
||||
}
|
||||
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), std::move(ssl_options));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -152,7 +152,11 @@ namespace epee
|
||||
{
|
||||
std::size_t space_needed = 0;
|
||||
for (const auto& source : sources)
|
||||
{
|
||||
if (std::numeric_limits<std::size_t>::max() - space_needed < source.size())
|
||||
throw std::bad_alloc{};
|
||||
space_needed += source.size();
|
||||
}
|
||||
|
||||
if (space_needed)
|
||||
{
|
||||
@@ -162,9 +166,9 @@ namespace epee
|
||||
|
||||
for (const auto& source : sources)
|
||||
{
|
||||
assert(source.size() <= out.size()); // see check above
|
||||
std::memcpy(out.data(), source.data(), source.size());
|
||||
if (out.remove_prefix(source.size()) < source.size())
|
||||
throw std::bad_alloc{}; // size_t overflow on space_needed
|
||||
out.remove_prefix(source.size());
|
||||
}
|
||||
storage_ = std::move(storage);
|
||||
}
|
||||
|
||||
@@ -46,12 +46,6 @@
|
||||
// TODO:
|
||||
#include "net/network_throttle-detail.hpp"
|
||||
|
||||
#if BOOST_VERSION >= 107000
|
||||
#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context())
|
||||
#else
|
||||
#define GET_IO_SERVICE(s) ((s).get_io_service())
|
||||
#endif
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.conn"
|
||||
|
||||
@@ -127,12 +121,12 @@ connection_basic_pimpl::connection_basic_pimpl(const std::string &name) : m_thro
|
||||
int connection_basic_pimpl::m_default_tos;
|
||||
|
||||
// methods:
|
||||
connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
|
||||
connection_basic::connection_basic(boost::asio::io_context &io_context, boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
|
||||
:
|
||||
m_state(std::move(state)),
|
||||
mI( new connection_basic_pimpl("peer") ),
|
||||
strand_(GET_IO_SERVICE(sock)),
|
||||
socket_(GET_IO_SERVICE(sock), get_context(m_state.get())),
|
||||
strand_(io_context),
|
||||
socket_(io_context, get_context(m_state.get())),
|
||||
m_want_close_connection(false),
|
||||
m_was_shutdown(false),
|
||||
m_is_multithreaded(false),
|
||||
@@ -152,12 +146,12 @@ connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, std::sha
|
||||
_note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_state->sock_count);
|
||||
}
|
||||
|
||||
connection_basic::connection_basic(boost::asio::io_service &io_service, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
|
||||
connection_basic::connection_basic(boost::asio::io_context &io_context, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
|
||||
:
|
||||
m_state(std::move(state)),
|
||||
mI( new connection_basic_pimpl("peer") ),
|
||||
strand_(io_service),
|
||||
socket_(io_service, get_context(m_state.get())),
|
||||
strand_(io_context),
|
||||
socket_(io_context, get_context(m_state.get())),
|
||||
m_want_close_connection(false),
|
||||
m_was_shutdown(false),
|
||||
m_is_multithreaded(false),
|
||||
|
||||
@@ -176,11 +176,12 @@ void mlog_configure(const std::string &filename_base, bool console, const std::s
|
||||
std::vector<boost::filesystem::path> found_files;
|
||||
const boost::filesystem::directory_iterator end_itr;
|
||||
const boost::filesystem::path filename_base_path(filename_base);
|
||||
const std::string filename_base_name = filename_base_path.filename().string();
|
||||
const boost::filesystem::path parent_path = filename_base_path.has_parent_path() ? filename_base_path.parent_path() : ".";
|
||||
for (boost::filesystem::directory_iterator iter(parent_path); iter != end_itr; ++iter)
|
||||
{
|
||||
const std::string filename = iter->path().string();
|
||||
if (filename.size() >= filename_base.size() && std::memcmp(filename.data(), filename_base.data(), filename_base.size()) == 0)
|
||||
const std::string filename = iter->path().filename().string();
|
||||
if (filename.size() >= filename_base_name.size() && std::memcmp(filename.data(), filename_base_name.data(), filename_base_name.size()) == 0)
|
||||
{
|
||||
found_files.push_back(iter->path());
|
||||
}
|
||||
|
||||
@@ -4,22 +4,38 @@ namespace epee
|
||||
{
|
||||
namespace net_utils
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct new_connection
|
||||
{
|
||||
boost::promise<boost::asio::ip::tcp::socket> result_;
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
template<typename T>
|
||||
explicit new_connection(T&& executor)
|
||||
: result_(), socket_(std::forward<T>(executor))
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
boost::unique_future<boost::asio::ip::tcp::socket>
|
||||
direct_connect::operator()(const std::string& addr, const std::string& port, boost::asio::steady_timer& timeout) const
|
||||
{
|
||||
// Get a list of endpoints corresponding to the server name.
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
boost::asio::ip::tcp::resolver resolver(GET_IO_SERVICE(timeout));
|
||||
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
boost::asio::ip::tcp::resolver resolver(MONERO_GET_EXECUTOR(timeout));
|
||||
|
||||
bool try_ipv6 = false;
|
||||
boost::asio::ip::tcp::resolver::iterator iterator;
|
||||
boost::asio::ip::tcp::resolver::iterator end;
|
||||
boost::asio::ip::tcp::resolver::results_type results{};
|
||||
boost::system::error_code resolve_error;
|
||||
|
||||
try
|
||||
{
|
||||
iterator = resolver.resolve(query, resolve_error);
|
||||
if(iterator == end) // Documentation states that successful call is guaranteed to be non-empty
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v4(), addr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
|
||||
);
|
||||
|
||||
if (results.empty())
|
||||
{
|
||||
// if IPv4 resolution fails, try IPv6. Unintentional outgoing IPv6 connections should only
|
||||
// be possible if for some reason a hostname was given and that hostname fails IPv4 resolution,
|
||||
@@ -37,27 +53,20 @@ namespace net_utils
|
||||
}
|
||||
try_ipv6 = true;
|
||||
}
|
||||
|
||||
if (try_ipv6)
|
||||
{
|
||||
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
|
||||
iterator = resolver.resolve(query6);
|
||||
if (iterator == end)
|
||||
results = resolver.resolve(
|
||||
boost::asio::ip::tcp::v6(), addr, port, boost::asio::ip::tcp::resolver::canonical_name
|
||||
);
|
||||
if (results.empty())
|
||||
throw boost::system::system_error{boost::asio::error::fault, "Failed to resolve " + addr};
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct new_connection
|
||||
{
|
||||
boost::promise<boost::asio::ip::tcp::socket> result_;
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
explicit new_connection(boost::asio::io_service& io_service)
|
||||
: result_(), socket_(io_service)
|
||||
{}
|
||||
};
|
||||
|
||||
const auto shared = std::make_shared<new_connection>(GET_IO_SERVICE(timeout));
|
||||
const auto shared = std::make_shared<new_connection>(MONERO_GET_EXECUTOR(timeout));
|
||||
timeout.async_wait([shared] (boost::system::error_code error)
|
||||
{
|
||||
if (error != boost::system::errc::operation_canceled && shared && shared->socket_.is_open())
|
||||
@@ -66,7 +75,7 @@ namespace net_utils
|
||||
shared->socket_.close();
|
||||
}
|
||||
});
|
||||
shared->socket_.async_connect(*iterator, [shared] (boost::system::error_code error)
|
||||
shared->socket_.async_connect(*results.begin(), [shared] (boost::system::error_code error)
|
||||
{
|
||||
if (shared)
|
||||
{
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <thread>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/cerrno.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
@@ -45,6 +46,13 @@
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "net.ssl"
|
||||
|
||||
|
||||
#if BOOST_VERSION >= 107300
|
||||
#define MONERO_HOSTNAME_VERIFY boost::asio::ssl::host_name_verification
|
||||
#else
|
||||
#define MONERO_HOSTNAME_VERIFY boost::asio::ssl::rfc2818_verification
|
||||
#endif
|
||||
|
||||
// openssl genrsa -out /tmp/KEY 4096
|
||||
// openssl req -new -key /tmp/KEY -out /tmp/REQ
|
||||
// openssl x509 -req -days 999999 -sha256 -in /tmp/REQ -signkey /tmp/KEY -out /tmp/CERT
|
||||
@@ -526,7 +534,7 @@ void ssl_options_t::configure(
|
||||
// preverified means it passed system or user CA check. System CA is never loaded
|
||||
// when fingerprints are whitelisted.
|
||||
const bool verified = preverified &&
|
||||
(verification != ssl_verification_t::system_ca || host.empty() || boost::asio::ssl::rfc2818_verification(host)(preverified, ctx));
|
||||
(verification != ssl_verification_t::system_ca || host.empty() || MONERO_HOSTNAME_VERIFY(host)(preverified, ctx));
|
||||
|
||||
if (!verified && !has_fingerprint(ctx))
|
||||
{
|
||||
@@ -544,6 +552,7 @@ void ssl_options_t::configure(
|
||||
}
|
||||
|
||||
bool ssl_options_t::handshake(
|
||||
boost::asio::io_context& io_context,
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket,
|
||||
boost::asio::ssl::stream_base::handshake_type type,
|
||||
boost::asio::const_buffer buffer,
|
||||
@@ -555,12 +564,11 @@ bool ssl_options_t::handshake(
|
||||
auto start_handshake = [&]{
|
||||
using ec_t = boost::system::error_code;
|
||||
using timer_t = boost::asio::steady_timer;
|
||||
using strand_t = boost::asio::io_service::strand;
|
||||
using strand_t = boost::asio::io_context::strand;
|
||||
using socket_t = boost::asio::ip::tcp::socket;
|
||||
|
||||
auto &io_context = GET_IO_SERVICE(socket);
|
||||
if (io_context.stopped())
|
||||
io_context.reset();
|
||||
io_context.restart();
|
||||
strand_t strand(io_context);
|
||||
timer_t deadline(io_context, timeout);
|
||||
|
||||
@@ -595,13 +603,13 @@ bool ssl_options_t::handshake(
|
||||
state.result = ec;
|
||||
if (!state.cancel_handshake) {
|
||||
state.cancel_timer = true;
|
||||
ec_t ec;
|
||||
deadline.cancel(ec);
|
||||
deadline.cancel();
|
||||
}
|
||||
};
|
||||
|
||||
deadline.async_wait(on_timer);
|
||||
strand.post(
|
||||
boost::asio::post(
|
||||
strand,
|
||||
[&]{
|
||||
socket.async_handshake(
|
||||
type,
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
#include "misc_log_ex.h"
|
||||
#include <boost/chrono.hpp>
|
||||
#include "misc_language.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -186,6 +186,23 @@ void network_throttle::handle_trafic_exact(size_t packet_size)
|
||||
_handle_trafic_exact(packet_size, packet_size);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct output_history
|
||||
{
|
||||
const boost::circular_buffer< network_throttle::packet_info >& history;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const output_history& source)
|
||||
{
|
||||
out << '[';
|
||||
for (auto sample: source.history)
|
||||
out << sample.m_size << ' ';
|
||||
out << ']';
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_size)
|
||||
{
|
||||
tick();
|
||||
@@ -196,14 +213,11 @@ void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_s
|
||||
m_total_packets++;
|
||||
m_total_bytes += packet_size;
|
||||
|
||||
std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends;
|
||||
std::string history_str = oss.str();
|
||||
|
||||
MTRACE("Throttle " << m_name << ": packet of ~"<<packet_size<<"b " << " (from "<<orginal_size<<" b)"
|
||||
<< " Speed AVG=" << std::setw(4) << ((long int)(cts .average/1024)) <<"[w="<<cts .window<<"]"
|
||||
<< " " << std::setw(4) << ((long int)(cts2.average/1024)) <<"[w="<<cts2.window<<"]"
|
||||
<<" / " << " Limit="<< ((long int)(m_target_speed/1024)) <<" KiB/sec "
|
||||
<< " " << history_str
|
||||
<< " " << output_history{m_history}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -289,8 +303,6 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc
|
||||
}
|
||||
|
||||
if (dbg) {
|
||||
std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends;
|
||||
std::string history_str = oss.str();
|
||||
MTRACE((cts.delay > 0 ? "SLEEP" : "")
|
||||
<< "dbg " << m_name << ": "
|
||||
<< "speed is A=" << std::setw(8) <<cts.average<<" vs "
|
||||
@@ -300,7 +312,7 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc
|
||||
<< "E="<< std::setw(8) << E << " (Enow="<<std::setw(8)<<Enow<<") "
|
||||
<< "M=" << std::setw(8) << M <<" W="<< std::setw(8) << cts.window << " "
|
||||
<< "R=" << std::setw(8) << cts.recomendetDataSize << " Wgood" << std::setw(8) << Wgood << " "
|
||||
<< "History: " << std::setw(8) << history_str << " "
|
||||
<< "History: " << std::setw(8) << output_history{m_history} << " "
|
||||
<< "m_last_sample_time=" << std::setw(8) << m_last_sample_time
|
||||
);
|
||||
|
||||
|
||||
@@ -38,9 +38,12 @@
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <system_error>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/utility/string_ref.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "misc_log_ex.h"
|
||||
#include "storages/parserse_base_utils.h"
|
||||
#include "hex.h"
|
||||
@@ -157,46 +160,20 @@ namespace string_tools
|
||||
return pname;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool set_module_name_and_folder(const std::string& path_to_process_)
|
||||
{
|
||||
std::string path_to_process = path_to_process_;
|
||||
|
||||
void set_module_name_and_folder(const std::string& path_to_process_)
|
||||
{
|
||||
boost::filesystem::path path_to_process = path_to_process_;
|
||||
|
||||
#ifdef _WIN32
|
||||
path_to_process = get_current_module_path();
|
||||
#endif
|
||||
std::string::size_type a = path_to_process.rfind( '\\' );
|
||||
if(a == std::string::npos )
|
||||
{
|
||||
a = path_to_process.rfind( '/' );
|
||||
}
|
||||
if ( a != std::string::npos )
|
||||
{
|
||||
get_current_module_name() = path_to_process.substr(a+1, path_to_process.size());
|
||||
get_current_module_folder() = path_to_process.substr(0, a);
|
||||
return true;
|
||||
}else
|
||||
return false;
|
||||
|
||||
}
|
||||
get_current_module_name() = path_to_process.filename().string();
|
||||
get_current_module_folder() = path_to_process.parent_path().string();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
bool trim_left(std::string& str)
|
||||
{
|
||||
for(std::string::iterator it = str.begin(); it!= str.end() && isspace(static_cast<unsigned char>(*it));)
|
||||
str.erase(str.begin());
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool trim_right(std::string& str)
|
||||
{
|
||||
|
||||
for(std::string::reverse_iterator it = str.rbegin(); it!= str.rend() && isspace(static_cast<unsigned char>(*it));)
|
||||
str.erase( --((it++).base()));
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string pad_string(std::string s, size_t n, char c, bool prepend)
|
||||
{
|
||||
if (s.size() < n)
|
||||
@@ -209,28 +186,22 @@ namespace string_tools
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string get_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('.');
|
||||
if(std::string::npos == pos)
|
||||
return res;
|
||||
|
||||
res = str.substr(pos+1, str.size()-pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
std::string cut_off_extension(const std::string& str)
|
||||
{
|
||||
std::string res;
|
||||
std::string::size_type pos = str.rfind('.');
|
||||
if(std::string::npos == pos)
|
||||
return str;
|
||||
std::string get_extension(const std::string& str)
|
||||
{
|
||||
std::string ext_with_dot = boost::filesystem::path(str).extension().string();
|
||||
|
||||
if (ext_with_dot.empty())
|
||||
return {};
|
||||
|
||||
return ext_with_dot.erase(0, 1);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
std::string cut_off_extension(const std::string& str)
|
||||
{
|
||||
return boost::filesystem::path(str).replace_extension("").string();
|
||||
}
|
||||
|
||||
res = str.substr(0, pos);
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
#ifdef _WIN32
|
||||
std::wstring utf8_to_utf16(const std::string& str)
|
||||
{
|
||||
|
||||
+1
Submodule external/mx25519 added at 84ca1290fa
+6
-6
@@ -4,6 +4,12 @@
|
||||
TAG=`git tag -l --points-at HEAD`
|
||||
COMMIT=`git rev-parse --short=9 HEAD`
|
||||
|
||||
# Build the 64-bit Windows release
|
||||
USE_DEVICE_TREZOR=OFF make depends target=x86_64-w64-mingw32 -j12
|
||||
pushd ./build/x86_64-w64-mingw32/release/bin > /dev/null
|
||||
zip -ur ~/releases/salvium-${TAG}-win64.zip salviumd.exe salvium-wallet-cli.exe salvium-wallet-rpc.exe
|
||||
popd > /dev/null
|
||||
|
||||
# Build the 64-bit Apple Silicon release
|
||||
USE_DEVICE_TREZOR=OFF make depends target=aarch64-apple-darwin -j12
|
||||
pushd ./build/aarch64-apple-darwin/release/bin > /dev/null
|
||||
@@ -22,10 +28,4 @@ pushd ./build/x86_64-linux-gnu/release/bin > /dev/null
|
||||
zip -ur ~/releases/salvium-${TAG}-linux-x86_64.zip salviumd salvium-wallet-cli salvium-wallet-rpc
|
||||
popd > /dev/null
|
||||
|
||||
# Build the 64-bit Windows release
|
||||
USE_DEVICE_TREZOR=OFF make depends target=x86_64-w64-mingw32 -j12
|
||||
pushd ./build/x86_64-w64-mingw32/release/bin > /dev/null
|
||||
zip -ur ~/releases/salvium-${TAG}-win64.zip salviumd.exe salvium-wallet-cli.exe salvium-wallet-rpc.exe
|
||||
popd > /dev/null
|
||||
|
||||
# Finish
|
||||
|
||||
@@ -267,8 +267,9 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, const std::vector<std::pair<transaction, blobdata>>& txs
|
||||
, const cryptonote::network_type& nettype
|
||||
, const cryptonote::network_type nettype
|
||||
, cryptonote::yield_block_info& ybi
|
||||
, cryptonote::audit_block_info& abi
|
||||
)
|
||||
{
|
||||
const block &blk = blck.first;
|
||||
@@ -295,7 +296,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
blobdata protocol_bd = tx_to_blob(blk.protocol_tx);
|
||||
add_transaction(blk_hash, std::make_pair(blk.protocol_tx, blobdata_ref(protocol_bd)));
|
||||
|
||||
if (blk.miner_tx.version == 2)
|
||||
if (blk.miner_tx.version >= 2)
|
||||
{
|
||||
num_rct_outs += blk.miner_tx.vout.size();
|
||||
|
||||
@@ -309,8 +310,8 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
}
|
||||
|
||||
std::map<std::string, int64_t> slippage_counts;
|
||||
uint64_t yield_total = 0;
|
||||
if (blk.protocol_tx.version == 2)
|
||||
uint64_t audit_total = 0, yield_total = 0;
|
||||
if (blk.protocol_tx.version >= 2)
|
||||
{
|
||||
num_rct_outs += blk.protocol_tx.vout.size();
|
||||
|
||||
@@ -355,11 +356,16 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
slippage_counts[asset_type] = 0;
|
||||
slippage_counts[asset_type] += tx.first.amount_burnt;
|
||||
}
|
||||
}
|
||||
|
||||
// Is this a YIELD TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::STAKE) {
|
||||
yield_total += tx.first.amount_burnt;
|
||||
}
|
||||
// Is this an AUDIT TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::AUDIT) {
|
||||
audit_total += tx.first.amount_burnt;
|
||||
}
|
||||
|
||||
// Is this a STAKE TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::STAKE) {
|
||||
yield_total += tx.first.amount_burnt;
|
||||
}
|
||||
++tx_i;
|
||||
}
|
||||
@@ -410,7 +416,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
|
||||
// call out to subclass implementation to add the block & metadata
|
||||
time1 = epee::misc_utils::get_tick_count();
|
||||
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, num_rct_outs_by_asset_type, blk_hash, slippage_total, yield_total, nettype, ybi);
|
||||
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, num_rct_outs_by_asset_type, blk_hash, slippage_total, yield_total, audit_total, nettype, ybi, abi);
|
||||
TIME_MEASURE_FINISH(time1);
|
||||
time_add_block1 += time1;
|
||||
|
||||
|
||||
@@ -430,8 +430,10 @@ private:
|
||||
const crypto::hash& blk_hash,
|
||||
uint64_t slippage_total,
|
||||
uint64_t yield_total,
|
||||
const cryptonote::network_type& nettype,
|
||||
cryptonote::yield_block_info& ybi
|
||||
uint64_t audit_total,
|
||||
const cryptonote::network_type nettype,
|
||||
cryptonote::yield_block_info& ybi,
|
||||
cryptonote::audit_block_info& abi
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
@@ -884,8 +886,9 @@ public:
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, const std::vector<std::pair<transaction, blobdata>>& txs
|
||||
, const cryptonote::network_type& nettype
|
||||
, const cryptonote::network_type nettype
|
||||
, cryptonote::yield_block_info& ybi
|
||||
, cryptonote::audit_block_info& abi
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -1915,6 +1918,9 @@ public:
|
||||
*/
|
||||
virtual uint64_t get_database_size() const = 0;
|
||||
|
||||
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const = 0;
|
||||
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const = 0;
|
||||
|
||||
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const = 0;
|
||||
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const = 0;
|
||||
|
||||
|
||||
@@ -29,14 +29,18 @@
|
||||
#include "db_lmdb.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/circular_buffer.hpp>
|
||||
|
||||
#include <memory> // std::unique_ptr
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winioctl.h>
|
||||
#endif
|
||||
|
||||
#include "string_tools.h"
|
||||
#include "file_io_utils.h"
|
||||
#include "common/util.h"
|
||||
#include "common/pruning.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
@@ -215,6 +219,9 @@ namespace
|
||||
* yield_block_data block height {slippage_coins, locked_coins, lc_total, network_health}
|
||||
* yield_tx_data block height {txn hash, locked_coins, return_address}
|
||||
*
|
||||
* audit_block_data block height {locked_coins, lc_total}
|
||||
* audit_tx_data block height {txn hash, locked_coins, return_address}
|
||||
*
|
||||
* Note: where the data items are of uniform size, DUPFIXED tables have
|
||||
* been used to save space. In most of these cases, a dummy "zerokval"
|
||||
* key is used when accessing the table; the Key listed above will be
|
||||
@@ -289,6 +296,8 @@ const char* const LMDB_CIRC_SUPPLY_TALLY = "circ_supply_tally";
|
||||
*/
|
||||
const char* const LMDB_YIELD_TXS = "yield_txs";
|
||||
const char* const LMDB_YIELD_BLOCKS = "yield_blocks";
|
||||
const char* const LMDB_AUDIT_TXS = "audit_txs";
|
||||
const char* const LMDB_AUDIT_BLOCKS = "audit_blocks";
|
||||
|
||||
const char zerokey[8] = {0};
|
||||
const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey };
|
||||
@@ -800,6 +809,75 @@ estim:
|
||||
return threshold_size;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_audit_block_info(const uint64_t height, audit_block_info& abi) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
// Clear the ABI, just in case
|
||||
std::memset(&abi, 0, sizeof(struct audit_block_info));
|
||||
|
||||
// Query for the matured AUDIT_BLOCK_INFO information
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(audit_blocks);
|
||||
|
||||
MDB_val v;
|
||||
MDB_val_set(k, height);
|
||||
int ret = mdb_cursor_get(m_cur_audit_blocks, &k, &v, MDB_SET);
|
||||
if (ret == MDB_NOTFOUND) {
|
||||
LOG_ERROR("Failed to locate ABI for block height " << height);
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit block info: ", ret).c_str()));
|
||||
|
||||
audit_block_info *p = (audit_block_info*)v.mv_data;
|
||||
abi = *p;
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
// Return success to caller
|
||||
return ret;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
// Clear the container
|
||||
ati_container.clear();
|
||||
|
||||
// Query for the (presumably matured) AUDIT_TX_INFO information (we actually reuse YIELD_TX_INFO for this)
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(audit_txs);
|
||||
|
||||
MDB_val v;
|
||||
MDB_val_set(k, height);
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
while (1)
|
||||
{
|
||||
int ret = mdb_cursor_get(m_cur_audit_txs, &k, &v, op);
|
||||
op = MDB_NEXT_DUP;
|
||||
if (ret == MDB_NOTFOUND)
|
||||
break;
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit TX info: ", ret).c_str()));
|
||||
|
||||
// Get the data
|
||||
yield_tx_info *p = (yield_tx_info*)v.mv_data;
|
||||
// Push result back into the container
|
||||
ati_container.emplace_back(*p);
|
||||
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
|
||||
ati_container.back().block_height = height;
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
// Return success to caller
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_yield_block_info(const uint64_t height, yield_block_info& ybi) const
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
@@ -855,9 +933,12 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate yield TX info: ", ret).c_str()));
|
||||
|
||||
// Push result back into the container
|
||||
// Get the data
|
||||
yield_tx_info *p = (yield_tx_info*)v.mv_data;
|
||||
// Push result back into the container
|
||||
yti_container.emplace_back(*p);
|
||||
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
|
||||
yti_container.back().block_height = height;
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
@@ -866,7 +947,7 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, const cryptonote::network_type& nettype, cryptonote::yield_block_info& ybi)
|
||||
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, uint64_t audit_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
@@ -896,6 +977,18 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
|
||||
|
||||
int result = 0;
|
||||
|
||||
// Create the AUDIT_BLOCK_INFO instance for this block
|
||||
CURSOR(audit_blocks)
|
||||
abi.block_height = m_height;
|
||||
abi.locked_coins_this_block = audit_total;
|
||||
|
||||
// Put the YBI into the table
|
||||
MDB_val_set(key, m_height);
|
||||
MDB_val_set(abi_val, abi);
|
||||
result = mdb_cursor_put(m_cur_audit_blocks, &key, &abi_val, MDB_APPEND);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to add ABI to db: ", result).c_str()));
|
||||
|
||||
CURSOR(yield_blocks)
|
||||
yield_block_info ybi_matured, ybi_prev;
|
||||
uint64_t yield_lock_period = cryptonote::get_config(nettype).STAKE_LOCK_PERIOD;
|
||||
@@ -932,7 +1025,6 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
|
||||
ybi.network_health_percentage = 100;
|
||||
|
||||
// Put the YBI into the table
|
||||
MDB_val_set(key, m_height);
|
||||
MDB_val_set(ybi_val, ybi);
|
||||
result = mdb_cursor_put(m_cur_yield_blocks, &key, &ybi_val, MDB_APPEND);
|
||||
if (result)
|
||||
@@ -1004,6 +1096,7 @@ void BlockchainLMDB::remove_block()
|
||||
CURSOR(blocks)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_blocks)
|
||||
CURSOR(audit_blocks)
|
||||
MDB_val_copy<uint64_t> k(m_height - 1);
|
||||
MDB_val h = k;
|
||||
if ((result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &h, MDB_GET_BOTH)))
|
||||
@@ -1031,6 +1124,11 @@ void BlockchainLMDB::remove_block()
|
||||
throw1(BLOCK_DNE(lmdb_error("Attempting to remove yield block info that's not in the db: ", result).c_str()));
|
||||
if ((result = mdb_cursor_del(m_cur_yield_blocks, 0)))
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of yield block info to db transaction: ", result).c_str()));
|
||||
|
||||
// Is the block within an audit window?
|
||||
if ((result = mdb_cursor_get(m_cur_audit_blocks, &k2, NULL, MDB_SET)) == 0)
|
||||
if ((result = mdb_cursor_del(m_cur_audit_blocks, 0)))
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit block info to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
boost::multiprecision::int128_t
|
||||
@@ -1116,6 +1214,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
CURSOR(circ_supply)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_txs)
|
||||
CURSOR(audit_txs)
|
||||
|
||||
MDB_val_set(val_tx_id, tx_id);
|
||||
MDB_val_set(val_h, tx_hash);
|
||||
@@ -1183,13 +1282,19 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
throw0(DB_ERROR(lmdb_error("Failed to add prunable tx prunable hash to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
|
||||
if (tx.type == cryptonote::transaction_type::MINER) {
|
||||
|
||||
// Update the circulating supply tally because of potentially burnt block_reward proportion
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
|
||||
std::string miner_asset_type = "SAL";
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
miner_asset_type = "SAL1";
|
||||
}
|
||||
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result && (m_height>0 || result != MDB_NOTFOUND))
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally;
|
||||
for (const auto& out: tx.vout) {
|
||||
@@ -1203,20 +1308,44 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent overflow
|
||||
if (burn_tally > burn_tally + tx.amount_burnt)
|
||||
throw0(DB_ERROR("burn overflow detected when adding miner_tx for db transaction"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent underflow
|
||||
if (source_tally < final_source_tally)
|
||||
throw0(DB_ERROR("numeric underflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally > final_burn_tally)
|
||||
throw0(DB_ERROR("burn overflow detected when adding tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
@@ -1240,17 +1369,25 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
MDB_val_copy<uint64_t> source_idx(asset.first);
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result)
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("minted asset not found"));
|
||||
else if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
if (source_tally > source_tally + asset.second)
|
||||
throw0(DB_ERROR("add_transaction_data() - mint overflow"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally + asset.second;
|
||||
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
|
||||
if (source_tally == 0 && result == MDB_NOTFOUND) {
|
||||
if (tx.source_asset_type == "SAL") {
|
||||
final_source_tally += coinbase;
|
||||
}
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before burn =" << source_tally.str() << "\n\tTally after burn =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
if (burn_tally < asset.second)
|
||||
throw0(DB_ERROR("add_transaction_data() - burn underflow"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1261,7 +1398,17 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
yield_tx_info yield_data;
|
||||
yield_data.block_height = m_height;
|
||||
yield_data.tx_hash = tx_hash;
|
||||
yield_data.return_address = tx.return_address;
|
||||
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
|
||||
if (tx.return_address == crypto::null_pkey)
|
||||
throw0(DB_ERROR("missing return_address entry (needed to create yield data for PROTOCOL_TX) - v2 STAKE"));
|
||||
yield_data.return_address = tx.return_address;
|
||||
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
if (tx.return_address_list.empty())
|
||||
throw0(DB_ERROR("no return_address_list entry (needed to create yield data for the PROTOCOL_TX)"));
|
||||
else if (tx.return_address_list.size() > 1)
|
||||
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create yield data for the PROTOCOL_TX)"));
|
||||
yield_data.return_address = tx.return_address_list[0];
|
||||
}
|
||||
yield_data.locked_coins = tx.amount_burnt;
|
||||
if (tx.vin.empty())
|
||||
throw0(DB_ERROR("tx.vin is empty (needed to create yield data for the PROTOCOL_TX)"));
|
||||
@@ -1298,6 +1445,60 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx yield data to db transaction: ", result).c_str() ));
|
||||
}
|
||||
|
||||
// Is there audit_tx data to add?
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// Create the object we are going to write to the database
|
||||
yield_tx_info audit_data;
|
||||
audit_data.block_height = m_height;
|
||||
audit_data.tx_hash = tx_hash;
|
||||
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
|
||||
if (tx.return_address == crypto::null_pkey)
|
||||
throw0(DB_ERROR("missing return_address entry (needed to create audit data for PROTOCOL_TX) - v2 STAKE"));
|
||||
audit_data.return_address = tx.return_address;
|
||||
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
if (tx.return_address_list.empty())
|
||||
throw0(DB_ERROR("no return_address_list entry (needed to create audit data for the PROTOCOL_TX)"));
|
||||
else if (tx.return_address_list.size() > 1)
|
||||
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create audit data for the PROTOCOL_TX)"));
|
||||
audit_data.return_address = tx.return_address_list[0];
|
||||
}
|
||||
audit_data.locked_coins = tx.amount_burnt;
|
||||
if (tx.vin.empty())
|
||||
throw0(DB_ERROR("tx.vin is empty (needed to create audit data for the PROTOCOL_TX)"));
|
||||
if (tx.vin[0].type() != typeid(cryptonote::txin_to_key))
|
||||
throw0(DB_ERROR("tx.vin[0] is wrong type (needed to create audit data for the PROTOCOL_TX)"));
|
||||
audit_data.return_pubkey = tx.return_pubkey;
|
||||
if (tx.vout.size() != 1)
|
||||
throw0(DB_ERROR("tx.vout is wrong size (needed to create audit data for the PROTOCOL_TX)"));
|
||||
if (!cryptonote::get_output_public_key(tx.vout[0], audit_data.P_change))
|
||||
throw0(DB_ERROR("failed to get P_change from tx.vout[0] (needed to create audit data for the PROTOCOL_TX)"));
|
||||
|
||||
// Because LMDB is shockingly bad at handling duplicates, we have resorted to using a counter of elements
|
||||
// in the first element of the struct.
|
||||
MDB_val data;
|
||||
MDB_val_set(val_height, m_height);
|
||||
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &data, MDB_SET);
|
||||
if (!result)
|
||||
{
|
||||
mdb_size_t num_elems = 0;
|
||||
result = mdb_cursor_count(m_cur_audit_txs, &num_elems);
|
||||
if (result)
|
||||
throw0(DB_ERROR(std::string("Failed to get number of audit TXs for height: ").append(mdb_strerror(result)).c_str()));
|
||||
audit_data.block_height = num_elems;
|
||||
}
|
||||
else if (result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str()));
|
||||
else
|
||||
audit_data.block_height = 0;
|
||||
|
||||
// Now we know how many there are, write out the data to the DB
|
||||
MDB_val_set(val_audit_tx_data, audit_data);
|
||||
result = mdb_cursor_put(m_cur_audit_txs, &val_height, &val_audit_tx_data, MDB_APPENDDUP);
|
||||
if (result)
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx audit data to db transaction: ", result).c_str() ));
|
||||
}
|
||||
|
||||
return tx_id;
|
||||
}
|
||||
|
||||
@@ -1320,6 +1521,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
CURSOR(tx_outputs)
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_txs)
|
||||
CURSOR(audit_txs)
|
||||
|
||||
MDB_val_set(val_h, tx_hash);
|
||||
|
||||
@@ -1363,42 +1565,70 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of prunable hash tx to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
|
||||
if (tx.type == cryptonote::transaction_type::MINER) {
|
||||
|
||||
// Update the circulating supply tally because of potentially burnt block_reward proportion
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
|
||||
std::string miner_asset_type = "SAL";
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
miner_asset_type = "SAL1";
|
||||
}
|
||||
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result && (m_height>0 || result != MDB_NOTFOUND))
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("remove_transaction_data() - Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally;
|
||||
for (const auto& out: tx.vout) {
|
||||
|
||||
// Sanity check - prevent underflow
|
||||
if (final_source_tally < final_source_tally - out.amount)
|
||||
throw0(DB_ERROR("remove_transaction_data() - numeric underflow detected when removing miner_tx for db transaction"));
|
||||
throw0(DB_ERROR("numeric underflow detected when removing miner_tx for db transaction"));
|
||||
|
||||
// Fetch the amount for this output
|
||||
final_source_tally -= out.amount;
|
||||
}
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally < tx.amount_burnt)
|
||||
throw0(DB_ERROR("burn underflow detected when removing miner_tx for db transaction"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
|
||||
// Sanity check - prevent overflow
|
||||
if (source_tally > source_tally + tx.amount_burnt + tx.rct_signatures.txnFee)
|
||||
throw0(DB_ERROR("remove_transaction_data() - numeric overflow detected when processing C/B/S for db transaction"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
// Sanity check - prevent overflow
|
||||
if (source_tally > final_source_tally)
|
||||
throw0(DB_ERROR("numeric overflow detected when processing C/B/S/A/T for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before remint =" << source_tally.str() << "\n\tTally after remint =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
|
||||
// Sanity check - prevent underflow
|
||||
if (burn_tally < (tx.amount_burnt + tx.rct_signatures.txnFee))
|
||||
throw0(DB_ERROR("burn underflow detected when removing tx for db transaction"));
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
@@ -1412,7 +1642,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
bool ok = cryptonote::get_output_asset_type(out, asset_type);
|
||||
if (!ok)
|
||||
throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)"));
|
||||
|
||||
minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount;
|
||||
}
|
||||
|
||||
@@ -1424,12 +1653,24 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
boost::multiprecision::int128_t source_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
|
||||
if (result == MDB_NOTFOUND)
|
||||
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
|
||||
throw0(DB_ERROR("minted asset not found"));
|
||||
else if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
if (source_tally < asset.second)
|
||||
throw0(DB_ERROR("remove_transaction_data() - mint underflow"));
|
||||
boost::multiprecision::int128_t final_source_tally = source_tally - asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
|
||||
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before undoing mint =" << source_tally.str() << "\n\tTally after undoing mint =" << final_source_tally.str());
|
||||
|
||||
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
|
||||
boost::multiprecision::int128_t burn_tally = 0;
|
||||
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
|
||||
if (burn_tally > burn_tally + asset.second)
|
||||
throw0(DB_ERROR("remove_transaction_data() - burn overflow"));
|
||||
boost::multiprecision::int128_t final_burn_tally = burn_tally + asset.second;
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
}
|
||||
remove_tx_outputs(tip->data.tx_id, tx);
|
||||
@@ -1446,7 +1687,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str()));
|
||||
}
|
||||
|
||||
// SRCG: The following code is designed to clean up the STAKE transactions, but it is very poorly written
|
||||
// SRCG: The following code is designed to clean up AUDIT+STAKE transactions, but it is very poorly written
|
||||
// Since transactions are ALWAYS supposed to be created in order, it stands that they should ALWAYS be
|
||||
// removed in REVERSE ORDER. Yet the following loop starts from the beginning - this is the worst possible
|
||||
// implementation in performance terms, since it will ALWAYS take the longest possible time to remove the
|
||||
@@ -1454,6 +1695,30 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
|
||||
// RECODE TO START FROM THE END OF THE DATABASE TABLE, AND THROW AN EXCEPTION IF YOU DO NOT MATCH FIRST TIME!
|
||||
|
||||
// Is there audit_tx data to remove?
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// Remove any yield_tx data for this transaction
|
||||
MDB_val_set(val_height, m_height);
|
||||
MDB_val v;
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
while (1) {
|
||||
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &v, op);
|
||||
if (result == MDB_NOTFOUND) {
|
||||
throw1(DB_ERROR("Failed to locate audit tx for removal from db transaction"));
|
||||
} else if (result) {
|
||||
throw1(DB_ERROR(lmdb_error("Failed to locate audit_tx data for removal: ", result).c_str()));
|
||||
}
|
||||
op = MDB_NEXT_DUP;
|
||||
const yield_tx_info ati = *(const yield_tx_info*)v.mv_data;
|
||||
if (ati.tx_hash == tx_hash) {
|
||||
result = mdb_cursor_del(m_cur_audit_txs, 0);
|
||||
if (result)
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit_tx data to db transaction: ", result).c_str()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is there yield_tx data to remove?
|
||||
if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
// Remove any yield_tx data for this transaction
|
||||
@@ -1822,6 +2087,54 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB()
|
||||
m_hardfork = nullptr;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
static bool disable_ntfs_compression(const boost::filesystem::path& filepath)
|
||||
{
|
||||
DWORD file_attributes = ::GetFileAttributesW(filepath.c_str());
|
||||
if (file_attributes == INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
MERROR("Failed to get " << filepath.string() << " file attributes. Error: " << ::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(file_attributes & FILE_ATTRIBUTE_COMPRESSED))
|
||||
return true; // not compressed
|
||||
|
||||
LOG_PRINT_L1("Disabling NTFS compression for " << filepath.string());
|
||||
HANDLE file_handle = ::CreateFileW(
|
||||
filepath.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
nullptr,
|
||||
OPEN_EXISTING,
|
||||
boost::filesystem::is_directory(filepath) ? FILE_FLAG_BACKUP_SEMANTICS : 0, // Needed to open handles to directories
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (file_handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
MERROR("Failed to open handle: " << filepath.string() << ". Error: " << ::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
USHORT compression_state = COMPRESSION_FORMAT_NONE;
|
||||
DWORD bytes_returned;
|
||||
BOOL ok = ::DeviceIoControl(
|
||||
file_handle,
|
||||
FSCTL_SET_COMPRESSION,
|
||||
&compression_state,
|
||||
sizeof(compression_state),
|
||||
nullptr,
|
||||
0,
|
||||
&bytes_returned,
|
||||
nullptr
|
||||
);
|
||||
|
||||
::CloseHandle(file_handle);
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
{
|
||||
int result;
|
||||
@@ -1848,6 +2161,18 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
throw DB_ERROR("Database could not be opened");
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
// ensure NTFS compression is disabled on the directory and database file to avoid corruption of the blockchain
|
||||
if (!disable_ntfs_compression(filename))
|
||||
LOG_PRINT_L0("Failed to disable NTFS compression on folder: " << filename << ". Error: " << ::GetLastError());
|
||||
boost::filesystem::path datafile(filename);
|
||||
datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
|
||||
if (!boost::filesystem::exists(datafile))
|
||||
boost::filesystem::ofstream(datafile).close(); // create the file to see if NTFS compression is enabled beforehand
|
||||
if (!disable_ntfs_compression(datafile))
|
||||
throw DB_ERROR("Database file is NTFS compressed and compression could not be disabled");
|
||||
#endif
|
||||
|
||||
boost::optional<bool> is_hdd_result = tools::is_hdd(filename.c_str());
|
||||
if (is_hdd_result)
|
||||
{
|
||||
@@ -1960,6 +2285,9 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
lmdb_db_open(txn, LMDB_YIELD_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_yield_txs, "Failed to open db handle for m_yield_txs");
|
||||
lmdb_db_open(txn, LMDB_YIELD_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_yield_blocks, "Failed to open db handle for m_yield_blocks");
|
||||
|
||||
lmdb_db_open(txn, LMDB_AUDIT_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_audit_txs, "Failed to open db handle for m_audit_txs");
|
||||
lmdb_db_open(txn, LMDB_AUDIT_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_audit_blocks, "Failed to open db handle for m_audit_blocks");
|
||||
|
||||
mdb_set_dupsort(txn, m_spent_keys, compare_hash32);
|
||||
mdb_set_dupsort(txn, m_block_heights, compare_hash32);
|
||||
mdb_set_dupsort(txn, m_tx_indices, compare_hash32);
|
||||
@@ -1983,6 +2311,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
mdb_set_compare(txn, m_circ_supply_tally, compare_uint64);
|
||||
|
||||
mdb_set_dupsort(txn, m_yield_txs, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_audit_txs, compare_uint64);
|
||||
|
||||
if (!(mdb_flags & MDB_RDONLY))
|
||||
{
|
||||
@@ -2164,6 +2493,10 @@ void BlockchainLMDB::reset()
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_txs: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_yield_blocks, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_blocks: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_audit_txs, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_txs: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_audit_blocks, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_blocks: ", result).c_str()));
|
||||
|
||||
// init with current version
|
||||
MDB_val_str(k, "version");
|
||||
@@ -3506,9 +3839,14 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
|
||||
// Check for SAL - we need to adjust the total for them
|
||||
if (currency_type == 0) {
|
||||
// Get the current circulating supply for SAL
|
||||
amount += m_coinbase;
|
||||
//amount += m_coinbase;
|
||||
}
|
||||
|
||||
if (amount < 0) {
|
||||
// Negative number can't be converted to a 64-bit UINT, so return 0, but retain -ve number privately
|
||||
LOG_PRINT_L2("BlockchainLMDB::" << __func__ << " - supply of " << currency_label << " is negative (" << amount << ") but outputting zero");
|
||||
amount = 0;
|
||||
}
|
||||
circulating_supply[currency_label] = amount.convert_to<uint64_t>();
|
||||
}
|
||||
|
||||
@@ -3517,12 +3855,13 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
|
||||
// NEAC: check for empty supply tally - only happens prior to first conversion on chain
|
||||
if (circulating_supply.empty()) {
|
||||
circulating_supply["SAL"] = m_coinbase;
|
||||
circulating_supply["SAL1"] = 0;
|
||||
circulating_supply["BURN"] = 0;
|
||||
}
|
||||
|
||||
// Adjust the supply to account for the staked coins
|
||||
circulating_supply["STAKE"] = staked_coins;
|
||||
|
||||
circulating_supply["BURN"] = m_coinbase - circulating_supply["SAL"] - circulating_supply["STAKE"];
|
||||
|
||||
return circulating_supply;
|
||||
}
|
||||
|
||||
@@ -4714,7 +5053,7 @@ void BlockchainLMDB::block_rtxn_abort() const
|
||||
}
|
||||
|
||||
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, const cryptonote::network_type& nettype, cryptonote::yield_block_info& ybi)
|
||||
const std::vector<std::pair<transaction, blobdata>>& txs, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
@@ -4732,7 +5071,7 @@ uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t
|
||||
|
||||
try
|
||||
{
|
||||
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi);
|
||||
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi, abi);
|
||||
}
|
||||
catch (const DB_ERROR_TXN_START& e)
|
||||
{
|
||||
@@ -5197,12 +5536,11 @@ bool BlockchainLMDB::is_read_only() const
|
||||
|
||||
uint64_t BlockchainLMDB::get_database_size() const
|
||||
{
|
||||
uint64_t size = 0;
|
||||
boost::filesystem::path datafile(m_folder);
|
||||
datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
|
||||
if (!epee::file_io_utils::get_file_size(datafile.string(), size))
|
||||
size = 0;
|
||||
return size;
|
||||
boost::system::error_code ec{};
|
||||
const boost::uintmax_t size = boost::filesystem::file_size(datafile, ec);
|
||||
return (ec ? 0 : static_cast<uint64_t>(size));
|
||||
}
|
||||
|
||||
#define RENAME_DB(name) do { \
|
||||
@@ -5229,8 +5567,38 @@ uint64_t BlockchainLMDB::get_database_size() const
|
||||
|
||||
#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global"))
|
||||
|
||||
void BlockchainLMDB::migrate_2_3()
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
uint64_t i;
|
||||
int result;
|
||||
mdb_txn_safe txn(false);
|
||||
MDB_val k, v;
|
||||
char *ptr;
|
||||
|
||||
MGINFO_YELLOW("Migrating blockchain from DB version 2 to 3 - this may take a while:");
|
||||
|
||||
// Create the missing (and empty) "audit_block_info" records for all blocks
|
||||
do {
|
||||
} while(0);
|
||||
|
||||
uint32_t version = VERSION;
|
||||
v.mv_data = (void *)&version;
|
||||
v.mv_size = sizeof(version);
|
||||
MDB_val_str(vk, "version");
|
||||
result = mdb_txn_begin(m_env, NULL, 0, txn);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
|
||||
result = mdb_put(txn, m_properties, &vk, &v, 0);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to update version for the db: ", result).c_str()));
|
||||
txn.commit();
|
||||
}
|
||||
|
||||
void BlockchainLMDB::migrate(const uint32_t oldversion)
|
||||
{
|
||||
//if (oldversion < 3)
|
||||
// migrate_2_3();
|
||||
}
|
||||
|
||||
} // namespace cryptonote
|
||||
|
||||
@@ -78,6 +78,8 @@ typedef struct mdb_txn_cursors
|
||||
MDB_cursor *m_txc_circ_supply_tally;
|
||||
MDB_cursor *m_txc_yield_txs;
|
||||
MDB_cursor *m_txc_yield_blocks;
|
||||
MDB_cursor *m_txc_audit_txs;
|
||||
MDB_cursor *m_txc_audit_blocks;
|
||||
|
||||
} mdb_txn_cursors;
|
||||
|
||||
@@ -104,6 +106,8 @@ typedef struct mdb_txn_cursors
|
||||
#define m_cur_circ_supply_tally m_cursors->m_txc_circ_supply_tally
|
||||
#define m_cur_yield_txs m_cursors->m_txc_yield_txs
|
||||
#define m_cur_yield_blocks m_cursors->m_txc_yield_blocks
|
||||
#define m_cur_audit_txs m_cursors->m_txc_audit_txs
|
||||
#define m_cur_audit_blocks m_cursors->m_txc_audit_blocks
|
||||
|
||||
typedef struct mdb_rflags
|
||||
{
|
||||
@@ -131,6 +135,8 @@ typedef struct mdb_rflags
|
||||
bool m_rf_circ_supply_tally;
|
||||
bool m_rf_yield_txs;
|
||||
bool m_rf_yield_blocks;
|
||||
bool m_rf_audit_txs;
|
||||
bool m_rf_audit_blocks;
|
||||
} mdb_rflags;
|
||||
|
||||
typedef struct mdb_threadinfo
|
||||
@@ -341,8 +347,9 @@ public:
|
||||
, const difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, const std::vector<std::pair<transaction, blobdata>>& txs
|
||||
, const cryptonote::network_type& nettype
|
||||
, const cryptonote::network_type nettype
|
||||
, cryptonote::yield_block_info& ybi
|
||||
, cryptonote::audit_block_info& abi
|
||||
);
|
||||
|
||||
virtual void set_batch_transactions(bool batch_transactions);
|
||||
@@ -400,8 +407,10 @@ private:
|
||||
const crypto::hash& blk_hash,
|
||||
uint64_t slippage_total,
|
||||
uint64_t yield_total,
|
||||
const cryptonote::network_type& nettype,
|
||||
cryptonote::yield_block_info& ybi
|
||||
uint64_t audit_total,
|
||||
const cryptonote::network_type nettype,
|
||||
cryptonote::yield_block_info& ybi,
|
||||
cryptonote::audit_block_info& abi
|
||||
);
|
||||
|
||||
virtual void remove_block();
|
||||
@@ -455,10 +464,14 @@ private:
|
||||
// migrate from older DB version to current
|
||||
void migrate(const uint32_t oldversion);
|
||||
|
||||
// migrate from DB version 0 to 1
|
||||
//void migrate_0_1();
|
||||
// migrate from DB version 2 to 3
|
||||
void migrate_2_3();
|
||||
|
||||
void cleanup_batch();
|
||||
|
||||
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const;
|
||||
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const;
|
||||
|
||||
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const;
|
||||
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const;
|
||||
|
||||
@@ -499,6 +512,9 @@ private:
|
||||
MDB_dbi m_yield_txs;
|
||||
MDB_dbi m_yield_blocks;
|
||||
|
||||
MDB_dbi m_audit_txs;
|
||||
MDB_dbi m_audit_blocks;
|
||||
|
||||
mutable uint64_t m_cum_size; // used in batch size estimation
|
||||
mutable unsigned int m_cum_count;
|
||||
std::string m_folder;
|
||||
|
||||
+32
-14
@@ -76,7 +76,7 @@ public:
|
||||
virtual uint64_t get_block_height(const crypto::hash& h) const override { return 0; }
|
||||
virtual cryptonote::block_header get_block_header(const crypto::hash& h) const override { return cryptonote::block_header(); }
|
||||
virtual uint64_t get_block_timestamp(const uint64_t& height) const override { return 0; }
|
||||
virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const override { return {}; }
|
||||
virtual std::pair<std::vector<uint64_t>, uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights, const std::string asset_type) const override { return {}; }
|
||||
virtual uint64_t get_top_block_timestamp() const override { return 0; }
|
||||
virtual size_t get_block_weight(const uint64_t& height) const override { return 128; }
|
||||
virtual std::vector<uint64_t> get_block_weights(uint64_t start_height, size_t count) const override { return {}; }
|
||||
@@ -92,6 +92,7 @@ public:
|
||||
virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const override { if (block_height) *block_height = 0; return crypto::hash(); }
|
||||
virtual cryptonote::block get_top_block() const override { return cryptonote::block(); }
|
||||
virtual uint64_t height() const override { return 1; }
|
||||
virtual std::map<std::string, uint64_t> get_circulating_supply() const override { return std::map<std::string, uint64_t>{}; }
|
||||
virtual bool tx_exists(const crypto::hash& h) const override { return false; }
|
||||
virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const override { return false; }
|
||||
virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const override { return 0; }
|
||||
@@ -101,20 +102,23 @@ public:
|
||||
virtual std::vector<cryptonote::transaction> get_tx_list(const std::vector<crypto::hash>& hlist) const override { return std::vector<cryptonote::transaction>(); }
|
||||
virtual uint64_t get_tx_block_height(const crypto::hash& h) const override { return 0; }
|
||||
virtual uint64_t get_num_outputs(const uint64_t& amount) const override { return 1; }
|
||||
virtual uint64_t get_num_outputs_of_asset_type(const std::string asset_type) const override { return 1; }
|
||||
virtual uint64_t get_indexing_base() const override { return 0; }
|
||||
virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const override { return cryptonote::output_data_t(); }
|
||||
virtual cryptonote::tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const override { return cryptonote::tx_out_index(); }
|
||||
virtual cryptonote::tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const override { return cryptonote::tx_out_index(); }
|
||||
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<cryptonote::tx_out_index> &indices) const override {}
|
||||
virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) const override {}
|
||||
virtual void get_output_id_from_asset_type_output_index(const std::string asset_type, const std::vector<uint64_t> &asset_type_output_indices, std::vector<uint64_t> &output_indices) const override {}
|
||||
virtual uint64_t get_output_id_from_asset_type_output_index(const std::string asset_type, const uint64_t &asset_type_output_index) const override { return 1; }
|
||||
virtual bool can_thread_bulk_indices() const override { return false; }
|
||||
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 std::vector<std::vector<std::pair<uint64_t, uint64_t>>> get_tx_amount_output_indices(const uint64_t tx_index, size_t n_txes) const override { return std::vector<std::vector<std::pair<uint64_t, 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_ref>& 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 {}
|
||||
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<cryptonote::transaction, cryptonote::blobdata_ref>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash, const bool miner_tx) override {return 0;}
|
||||
virtual void remove_transaction_data(const crypto::hash& tx_hash, const cryptonote::transaction& tx, const bool miner_tx) override {}
|
||||
virtual std::pair<uint64_t, 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 std::make_pair(0,0);}
|
||||
virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<std::pair<uint64_t, uint64_t>>& amount_output_indices) override {}
|
||||
virtual void add_spent_key(const crypto::key_image& k_image) override {}
|
||||
virtual void remove_spent_key(const crypto::key_image& k_image) override {}
|
||||
|
||||
@@ -135,17 +139,31 @@ public:
|
||||
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, relay_category tx_category) const override { return false; }
|
||||
virtual uint64_t get_database_size() const override { return 0; }
|
||||
|
||||
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const override { return 0; }
|
||||
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const override { return 0; }
|
||||
|
||||
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const override { return 0; }
|
||||
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const override { return 0; }
|
||||
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const override { return ""; }
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata_ref*)>, bool include_blob = false, relay_category category = relay_category::broadcasted) const override { return false; }
|
||||
|
||||
virtual void add_block( const cryptonote::block& blk
|
||||
, size_t block_weight
|
||||
, uint64_t long_term_block_weight
|
||||
, const cryptonote::difficulty_type& cumulative_difficulty
|
||||
, const uint64_t& coins_generated
|
||||
, uint64_t num_rct_outs
|
||||
, const crypto::hash& blk_hash
|
||||
) override { }
|
||||
virtual void add_block( const block& blk,
|
||||
size_t block_weight,
|
||||
uint64_t long_term_block_weight,
|
||||
const difficulty_type& cumulative_difficulty,
|
||||
const uint64_t& coins_generated,
|
||||
uint64_t num_rct_outs,
|
||||
oracle::asset_type_counts& cum_rct_by_asset_type,
|
||||
const crypto::hash& blk_hash,
|
||||
uint64_t slippage_total,
|
||||
uint64_t yield_total,
|
||||
uint64_t audit_total,
|
||||
const cryptonote::network_type nettype,
|
||||
cryptonote::yield_block_info& ybi,
|
||||
cryptonote::audit_block_info& abi
|
||||
) override { }
|
||||
virtual cryptonote::block get_block_from_height(const uint64_t& height) const override { return cryptonote::block(); }
|
||||
virtual void set_hard_fork_version(uint64_t height, uint8_t version) override {}
|
||||
virtual uint8_t get_hard_fork_version(uint64_t height) const override { return 0; }
|
||||
|
||||
@@ -133,6 +133,31 @@ monero_private_headers(blockchain_stats
|
||||
${blockchain_stats_private_headers})
|
||||
|
||||
|
||||
set(blockchain_scanner_sources
|
||||
blockchain_scanner.cpp
|
||||
)
|
||||
|
||||
set(blockchain_scanner_private_headers)
|
||||
|
||||
monero_private_headers(blockchain_scanner
|
||||
${blockchain_scanner_private_headers})
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
|
||||
set(blockchain_audit_sources
|
||||
blockchain_audit.cpp
|
||||
threadpool_boost.cpp
|
||||
)
|
||||
|
||||
set(blockchain_audit_private_headers
|
||||
threadpool_boost.h
|
||||
)
|
||||
|
||||
monero_private_headers(blockchain_audit
|
||||
${blockchain_audit_private_headers})
|
||||
else()
|
||||
message(STATUS "blockchain_audit.cpp not found - not building the audit tool")
|
||||
endif()
|
||||
|
||||
monero_add_executable(blockchain_import
|
||||
${blockchain_import_sources}
|
||||
${blockchain_import_private_headers})
|
||||
@@ -281,6 +306,56 @@ set_property(TARGET blockchain_depth
|
||||
OUTPUT_NAME "salvium-blockchain-depth")
|
||||
install(TARGETS blockchain_depth DESTINATION bin)
|
||||
|
||||
monero_add_executable(blockchain_scanner
|
||||
${blockchain_scanner_sources}
|
||||
${blockchain_scanner_private_headers})
|
||||
|
||||
target_link_libraries(blockchain_scanner
|
||||
PRIVATE
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
version
|
||||
epee
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
set_property(TARGET blockchain_scanner
|
||||
PROPERTY
|
||||
OUTPUT_NAME "salvium-blockchain-scanner")
|
||||
install(TARGETS blockchain_scanner DESTINATION bin)
|
||||
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
|
||||
monero_add_executable(blockchain_audit
|
||||
${blockchain_audit_sources}
|
||||
${blockchain_audit_private_headers})
|
||||
|
||||
target_include_directories(blockchain_audit PRIVATE /usr/include/mysql-cppconn/jdbc)
|
||||
|
||||
target_link_libraries(blockchain_audit
|
||||
PRIVATE
|
||||
wallet
|
||||
crypto
|
||||
cncrypto
|
||||
cryptonote_core
|
||||
blockchain_db
|
||||
version
|
||||
epee
|
||||
mysqlcppconn
|
||||
${Boost_FILESYSTEM_LIBRARY}
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
set_property(TARGET blockchain_audit
|
||||
PROPERTY
|
||||
OUTPUT_NAME "salvium-blockchain-audit")
|
||||
install(TARGETS blockchain_audit DESTINATION bin)
|
||||
endif()
|
||||
|
||||
monero_add_executable(blockchain_stats
|
||||
${blockchain_stats_sources}
|
||||
${blockchain_stats_private_headers})
|
||||
|
||||
@@ -488,8 +488,9 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
|
||||
try
|
||||
{
|
||||
cryptonote::yield_block_info ybi; // This just gets discarded because we aren't looking to maintain a cache of YBI data in the import utility
|
||||
cryptonote::audit_block_info abi; // This just gets discarded because we aren't looking to maintain a cache of ABI data in the import utility
|
||||
uint64_t long_term_block_weight = core.get_blockchain_storage().get_next_long_term_block_weight(block_weight);
|
||||
core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, ybi);
|
||||
core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, ybi, abi);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
// 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.
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include "common/command_line.h"
|
||||
#include "common/i18n.h"
|
||||
#include "common/password.h"
|
||||
#include "common/varint.h"
|
||||
#include "cryptonote_basic/cryptonote_boost_serialization.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_core/cryptonote_tx_utils.h"
|
||||
#include "cryptonote_core/blockchain.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "oracle/pricing_record.h"
|
||||
#include "version.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
|
||||
|
||||
#define DELIM "|"
|
||||
#define DEF_STAKE_MODE "all"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
using namespace epee;
|
||||
using namespace cryptonote;
|
||||
|
||||
namespace scanner
|
||||
{
|
||||
const char* tr(const char* str)
|
||||
{
|
||||
return i18n_translate(str, "tools::scanner");
|
||||
}
|
||||
}
|
||||
|
||||
static bool stop_requested = false;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
TRY_ENTRY();
|
||||
|
||||
epee::string_tools::set_module_name_and_folder(argv[0]);
|
||||
|
||||
uint32_t log_level = 0;
|
||||
uint64_t block_start = 0;
|
||||
uint64_t block_stop = 0;
|
||||
|
||||
tools::on_startup();
|
||||
|
||||
boost::filesystem::path output_file_path;
|
||||
|
||||
po::options_description desc_cmd_only("Command line options");
|
||||
po::options_description desc_cmd_sett("Command line options and settings options");
|
||||
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
|
||||
const command_line::arg_descriptor<uint64_t> arg_block_start = {"block-start", "start at block number", block_start};
|
||||
const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
|
||||
const command_line::arg_descriptor<std::string> arg_delimiter = {"delimiter", "\"<string>\"", DELIM};
|
||||
const command_line::arg_descriptor<std::string> arg_stake_mode = {"stake", "\"<string>\"", DEF_STAKE_MODE};
|
||||
const command_line::arg_descriptor<bool> arg_check_asset_types = {"check-asset-types", "Scan for asset-type issues", false};
|
||||
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
|
||||
command_line::add_arg(desc_cmd_sett, cryptonote::arg_stagenet_on);
|
||||
command_line::add_arg(desc_cmd_sett, arg_log_level);
|
||||
command_line::add_arg(desc_cmd_sett, arg_block_start);
|
||||
command_line::add_arg(desc_cmd_sett, arg_block_stop);
|
||||
command_line::add_arg(desc_cmd_sett, arg_delimiter);
|
||||
command_line::add_arg(desc_cmd_sett, arg_stake_mode);
|
||||
command_line::add_arg(desc_cmd_sett, arg_check_asset_types);
|
||||
command_line::add_arg(desc_cmd_only, command_line::arg_help);
|
||||
|
||||
po::options_description desc_options("Allowed options");
|
||||
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
|
||||
|
||||
po::variables_map vm;
|
||||
bool r = command_line::handle_error_helper(desc_options, [&]()
|
||||
{
|
||||
auto parser = po::command_line_parser(argc, argv).options(desc_options);
|
||||
po::store(parser.run(), vm);
|
||||
po::notify(vm);
|
||||
return true;
|
||||
});
|
||||
if (! r)
|
||||
return 1;
|
||||
|
||||
if (command_line::get_arg(vm, command_line::arg_help))
|
||||
{
|
||||
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
|
||||
std::cout << desc_options << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
mlog_configure(mlog_get_default_log_path("monero-blockchain-stats.log"), true);
|
||||
if (!command_line::is_arg_defaulted(vm, arg_log_level))
|
||||
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
|
||||
else
|
||||
mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
|
||||
|
||||
LOG_PRINT_L0("Starting...");
|
||||
|
||||
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_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
|
||||
network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
|
||||
block_start = command_line::get_arg(vm, arg_block_start);
|
||||
block_stop = command_line::get_arg(vm, arg_block_stop);
|
||||
std::string delimiter = command_line::get_arg(vm, arg_delimiter);
|
||||
std::string stake_mode = command_line::get_arg(vm, arg_stake_mode);
|
||||
bool opt_check_asset_types = command_line::get_arg(vm, arg_check_asset_types);
|
||||
|
||||
// If we wanted to use the memory pool, we would set up a fake_core.
|
||||
|
||||
// Use Blockchain instead of lower-level BlockchainDB for two reasons:
|
||||
// 1. Blockchain has the init() method for easy setup
|
||||
// 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
|
||||
//
|
||||
// cannot match blockchain_storage setup above with just one line,
|
||||
// e.g.
|
||||
// Blockchain* core_storage = new Blockchain(NULL);
|
||||
// because unlike blockchain_storage constructor, which takes a pointer to
|
||||
// tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
|
||||
LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
|
||||
std::unique_ptr<BlockchainAndPool> core_storage = std::make_unique<BlockchainAndPool>();
|
||||
|
||||
BlockchainDB* db = new_db();
|
||||
if (db == NULL)
|
||||
{
|
||||
LOG_ERROR("Failed to initialize a database");
|
||||
throw std::runtime_error("Failed to initialize a database");
|
||||
}
|
||||
LOG_PRINT_L0("database: LMDB");
|
||||
|
||||
boost::filesystem::path folder(opt_data_dir);
|
||||
if (opt_stagenet) {
|
||||
folder /= std::to_string(STAGENET_VERSION);
|
||||
} else if (opt_testnet) {
|
||||
folder /= std::to_string(TESTNET_VERSION);
|
||||
}
|
||||
folder /= db->get_db_name();
|
||||
LOG_PRINT_L0("Loading blockchain from folder " << folder << " ...");
|
||||
const std::string filename = folder.string();
|
||||
|
||||
try
|
||||
{
|
||||
db->open(filename, DBF_RDONLY);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_PRINT_L0("Error opening database: " << e.what());
|
||||
return 1;
|
||||
}
|
||||
r = core_storage->blockchain.init(db, net_type);
|
||||
|
||||
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
|
||||
LOG_PRINT_L0("Source blockchain storage initialized OK");
|
||||
|
||||
tools::signal_handler::install([](int type) {
|
||||
stop_requested = true;
|
||||
});
|
||||
|
||||
const uint64_t db_height = db->height();
|
||||
if (!block_stop)
|
||||
block_stop = db_height;
|
||||
MINFO("Starting from height " << block_start << ", stopping at height " << block_stop);
|
||||
|
||||
/*
|
||||
* The default output can be plotted with GnuPlot using these commands:
|
||||
set key autotitle columnhead
|
||||
set title "Salvium Blockchain Growth"
|
||||
set timefmt "%Y-%m-%d"
|
||||
set xdata time
|
||||
set xrange ["2014-04-17":*]
|
||||
set format x "%Y-%m-%d"
|
||||
set yrange [0:*]
|
||||
set y2range [0:*]
|
||||
set ylabel "Txs/Day"
|
||||
set y2label "Bytes"
|
||||
set y2tics nomirror
|
||||
plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, '' using (timecolumn(1,"%Y-%m-%d")):7 axes x1y2 with lines
|
||||
*/
|
||||
|
||||
// spit out a comment that GnuPlot can use as an index
|
||||
std::cout << ENDL << "# DATA" << ENDL;
|
||||
std::cout << "Date" << delimiter << "Height" << delimiter << "Transaction ID" << delimiter << "Reason" << delimiter << "Extra Information";
|
||||
std::cout << ENDL;
|
||||
|
||||
#define MAX_INOUT 0xffffffff
|
||||
#define MAX_RINGS 0xffffffff
|
||||
|
||||
struct tm prevtm = {0}, currtm;
|
||||
uint64_t prevsz = 0, currsz = 0;
|
||||
uint64_t prevtxs = 0, currtxs = 0;
|
||||
uint64_t currblks = 0;
|
||||
uint32_t txhr[24] = {0};
|
||||
unsigned int i;
|
||||
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(net_type).AUDIT_HARD_FORKS;
|
||||
|
||||
for (uint64_t h = block_start; h < block_stop; ++h)
|
||||
{
|
||||
cryptonote::blobdata bd = db->get_block_blob_from_height(h);
|
||||
cryptonote::block blk;
|
||||
if (!cryptonote::parse_and_validate_block_from_blob(bd, blk))
|
||||
{
|
||||
LOG_PRINT_L0("Bad block from db");
|
||||
return 1;
|
||||
}
|
||||
time_t tt = blk.timestamp;
|
||||
char timebuf[64];
|
||||
epee::misc_utils::get_gmt_time(tt, currtm);
|
||||
if (!prevtm.tm_year)
|
||||
prevtm = currtm;
|
||||
// catch change of day
|
||||
if (currtm.tm_mday > prevtm.tm_mday || (currtm.tm_mday == 1 && prevtm.tm_mday > 27))
|
||||
{
|
||||
// check for timestamp fudging around month ends
|
||||
if (prevtm.tm_mday == 1 && currtm.tm_mday > 27)
|
||||
goto skip;
|
||||
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d", &currtm);
|
||||
prevtm = currtm;
|
||||
}
|
||||
skip:
|
||||
currsz += bd.size();
|
||||
uint64_t coinbase_amount;
|
||||
uint64_t tx_fee_amount = 0;
|
||||
std::set<std::string> used_assets, miner_tx_assets, protocol_tx_assets;
|
||||
std::map<size_t, std::vector<std::string>> used_tx_versions;
|
||||
used_assets.insert("SAL");
|
||||
|
||||
uint8_t hf_version = blk.major_version;
|
||||
|
||||
// Check TX versions
|
||||
if (blk.miner_tx.version != 2) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX version detected" << delimiter << "version:" << blk.miner_tx.version << std::endl;
|
||||
}
|
||||
if (blk.protocol_tx.version != 2 && h>0) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX version detected" << delimiter << "version:" << blk.protocol_tx.version << std::endl;
|
||||
}
|
||||
|
||||
// Get the miner_tx assets
|
||||
std::set<crypto::public_key> used_keys;
|
||||
for (const auto& miner_tx_vout : blk.miner_tx.vout) {
|
||||
std::string asset_type;
|
||||
if (!cryptonote::get_output_asset_type(miner_tx_vout, asset_type)) {
|
||||
throw std::runtime_error("Aborting: failed to get output asset type from miner_tx");
|
||||
} else if (blk.major_version >= HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL1") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from miner_tx: " + asset_type);
|
||||
} else if (blk.major_version < HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from miner_tx: " + asset_type + ", HF:" + std::to_string(blk.major_version));
|
||||
}
|
||||
miner_tx_assets.insert(asset_type);
|
||||
if (miner_tx_vout.amount > 13500000000 && h>0) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX amount detected" << delimiter << "amount:" << miner_tx_vout.amount << std::endl;
|
||||
}
|
||||
crypto::public_key key;
|
||||
cryptonote::get_output_public_key(miner_tx_vout, key);
|
||||
if (used_keys.count(key)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX - duplicate output detected" << delimiter << "pubkey:" << key << std::endl;
|
||||
}
|
||||
used_keys.insert(key);
|
||||
}
|
||||
|
||||
// Get the protocol_tx assets
|
||||
used_keys.clear();
|
||||
for (const auto& protocol_tx_vout : blk.protocol_tx.vout) {
|
||||
std::string asset_type;
|
||||
if (!cryptonote::get_output_asset_type(protocol_tx_vout, asset_type)) {
|
||||
throw std::runtime_error("Aborting: failed to get output asset type from protocol_tx");
|
||||
} else if (blk.major_version >= HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL1") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx: " + asset_type);
|
||||
} else if (blk.major_version < HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx: " + asset_type + ", HF:" + std::to_string(blk.major_version));
|
||||
}
|
||||
protocol_tx_assets.insert(asset_type);
|
||||
if (protocol_tx_vout.amount > 25000000000000) {
|
||||
//std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "large protocol TX amount detected from height " << (h-audit_lock_period) << delimiter << "amount:" << protocol_tx_vout.amount << std::endl;
|
||||
}
|
||||
crypto::public_key key;
|
||||
cryptonote::get_output_public_key(protocol_tx_vout, key);
|
||||
if (used_keys.count(key)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX - duplicate output detected" << delimiter << "pubkey:" << key << std::endl;
|
||||
}
|
||||
used_keys.insert(key);
|
||||
}
|
||||
|
||||
for (const auto& tx_id : blk.tx_hashes)
|
||||
{
|
||||
if (tx_id == crypto::null_hash)
|
||||
{
|
||||
throw std::runtime_error("Aborting: tx == null_hash");
|
||||
}
|
||||
if (!db->get_pruned_tx_blob(tx_id, bd))
|
||||
{
|
||||
throw std::runtime_error("Aborting: tx not found");
|
||||
}
|
||||
transaction tx;
|
||||
if (!parse_and_validate_tx_base_from_blob(bd, tx))
|
||||
{
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX detected" << delimiter << std::endl;
|
||||
continue;
|
||||
}
|
||||
currsz += bd.size();
|
||||
if (db->get_prunable_tx_blob(tx_id, bd))
|
||||
currsz += bd.size();
|
||||
currtxs++;
|
||||
|
||||
if (tx.type != cryptonote::transaction_type::TRANSFER &&
|
||||
tx.type != cryptonote::transaction_type::BURN &&
|
||||
tx.type != cryptonote::transaction_type::STAKE &&
|
||||
tx.type != cryptonote::transaction_type::AUDIT) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX type detected" << delimiter << "type:" << (uint8_t)tx.type << std::endl;
|
||||
}
|
||||
|
||||
if ((tx.version != 2 && hf_version < HF_VERSION_ENABLE_N_OUTS) || (tx.version != 3 && hf_version < HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER)) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX version detected" << delimiter << "version:" << tx.version << std::endl;
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::STAKE && stake_mode.compare("off")) {
|
||||
if (stake_mode.compare("all") == 0) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "STAKE TX detected" << delimiter << "amount:" << (tx.amount_burnt / 100000000) << std::endl;
|
||||
} else if (stake_mode.compare("large") == 0 && tx.amount_burnt > 25000000000000llu) {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "large STAKE TX detected" << delimiter << "amount:" << (tx.amount_burnt / 100000000) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_check_asset_types) {
|
||||
if (tx.source_asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid source asset type found in tx");
|
||||
} else if (tx.destination_asset_type != "SAL") {
|
||||
if (tx.destination_asset_type == "BURN") {
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "BURN TX detected" << delimiter << "amount:" << tx.amount_burnt << std::endl;
|
||||
} else {
|
||||
throw std::runtime_error("Aborting: invalid destination asset type found in tx");
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& tx_vout : tx.vout) {
|
||||
std::string asset_type;
|
||||
if (!cryptonote::get_output_asset_type(tx_vout, asset_type)) {
|
||||
throw std::runtime_error("Aborting: failed to get output asset type from tx");
|
||||
} else if (asset_type != "SAL") {
|
||||
throw std::runtime_error("Aborting: invalid output asset type from tx");
|
||||
}
|
||||
}
|
||||
|
||||
// Add the source currency to the list of expected ones
|
||||
used_assets.insert(tx.source_asset_type);
|
||||
}
|
||||
}
|
||||
|
||||
currblks++;
|
||||
|
||||
if (stop_requested)
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
CATCH_ENTRY("Stats reporting error", 1);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <iostream>
|
||||
#include "threadpool_boost.h"
|
||||
|
||||
ThreadPool::ThreadPool(size_t numThreads)
|
||||
: workGuard(boost::asio::make_work_guard(ioService)) {
|
||||
for (size_t i = 0; i < numThreads; ++i) {
|
||||
workers.emplace_back([this]() {
|
||||
std::cerr << "Thread started" << std::endl;
|
||||
ioService.run();
|
||||
std::cerr << "Thread finished" << std::endl;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadPool::enqueue(std::function<void()> task) {
|
||||
ioService.post([task]() {
|
||||
try {
|
||||
task(); // Run the task
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception in thread pool task: " << e.what() << std::endl;
|
||||
} catch (...) {
|
||||
std::cerr << "Unknown exception in thread pool task!" << std::endl;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ThreadPool::isStopping() const {
|
||||
return ioService.stopped(); // Check if io_context has stopped
|
||||
}
|
||||
|
||||
void ThreadPool::waitForCompletion() {
|
||||
std::cout << "Waiting for completion...\n";
|
||||
workGuard.reset(); // Allow ioService to stop when no more tasks
|
||||
ioService.run(); // Ensure no threads are left hanging
|
||||
|
||||
for (auto &worker : workers) {
|
||||
if (worker.joinable()) worker.join();
|
||||
}
|
||||
std::cout << "All threads joined.\n";
|
||||
}
|
||||
|
||||
ThreadPool::~ThreadPool() {
|
||||
waitForCompletion();
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef THREADPOOL_BOOST_H
|
||||
#define THREADPOOL_BOOST_H
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
class ThreadPool {
|
||||
public:
|
||||
explicit ThreadPool(size_t numThreads);
|
||||
~ThreadPool();
|
||||
|
||||
void enqueue(std::function<void()> task);
|
||||
bool isStopping() const;
|
||||
void waitForCompletion();
|
||||
|
||||
private:
|
||||
boost::asio::io_service ioService;
|
||||
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> workGuard;
|
||||
std::vector<boost::thread> workers;
|
||||
};
|
||||
|
||||
#endif // THREADPOOL_BOOST_H
|
||||
Binary file not shown.
@@ -204,6 +204,7 @@ namespace cryptonote
|
||||
ADD_CHECKPOINT2(180, "e20bc8ac6aabb6b0792f23a29ce42a577c6a57d177a8ac1a51b68fb6de508045", "0x262b40");
|
||||
ADD_CHECKPOINT2(190, "f69fdad7a15471b63a82668b618ee5b2a384291269d944b11974a723c1604124", "0x2856a3");
|
||||
ADD_CHECKPOINT2(200, "eba53fa7006dfcdc837a56c0bc8f0e1883cf34861c26934d680252a6878a3f5d", "0x2aa022");
|
||||
ADD_CHECKPOINT2(90000, "e125b5c1b26521f98e29df6ec88f041c176a2c0a3fcacd5bd0ad2278e9b02fd2", "0xc99801f937888"); // 3546475285149832
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include <atomic>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include "file_io_utils.h"
|
||||
#include "net/http_client.h"
|
||||
#include "download.h"
|
||||
|
||||
@@ -73,8 +72,11 @@ namespace tools
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(control->mutex);
|
||||
std::ios_base::openmode mode = std::ios_base::out | std::ios_base::binary;
|
||||
uint64_t existing_size = 0;
|
||||
if (epee::file_io_utils::get_file_size(control->path, existing_size) && existing_size > 0)
|
||||
boost::system::error_code ec{};
|
||||
uint64_t existing_size = static_cast<uint64_t>(boost::filesystem::file_size(control->path, ec));
|
||||
if (ec)
|
||||
existing_size = 0;
|
||||
if (existing_size > 0)
|
||||
{
|
||||
MINFO("Resuming downloading " << control->uri << " to " << control->path << " from " << existing_size);
|
||||
mode |= std::ios_base::app;
|
||||
|
||||
@@ -185,7 +185,7 @@ namespace
|
||||
return false;
|
||||
if (verify)
|
||||
{
|
||||
std::cout << "Confirm password: ";
|
||||
std::cout << "Confirm password: " << std::flush;
|
||||
if (!read_from_tty(pass2, hide_input))
|
||||
return false;
|
||||
if(pass1!=pass2)
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "easylogging++/easylogging++.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iomanip>
|
||||
#ifdef USE_UNWIND
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include <libunwind.h>
|
||||
|
||||
+1
-1
@@ -664,7 +664,7 @@ namespace tools
|
||||
}
|
||||
|
||||
boost::system::error_code ec;
|
||||
const auto parsed_ip = boost::asio::ip::address::from_string(u_c.host, ec);
|
||||
const auto parsed_ip = boost::asio::ip::make_address(u_c.host, ec);
|
||||
if (ec) {
|
||||
MDEBUG("Failed to parse '" << address << "' as IP address: " << ec.message() << ". Considering it not local");
|
||||
return false;
|
||||
|
||||
@@ -71,7 +71,7 @@ target_link_libraries(cncrypto
|
||||
epee
|
||||
randomx
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${sodium_LIBRARIES}
|
||||
${SODIUM_LIBRARY}
|
||||
PRIVATE
|
||||
${EXTRA_LIBRARIES})
|
||||
|
||||
|
||||
+20
-4
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2014-2022, The Monero Project
|
||||
// Copyright (c) 2014-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -171,7 +171,9 @@ namespace crypto {
|
||||
/* Generate a value filled with random bytes.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_pod<T>::value, T>::type rand() {
|
||||
T rand() {
|
||||
static_assert(std::is_standard_layout<T>(), "cannot write random bytes into non-standard layout type");
|
||||
static_assert(std::is_trivially_copyable<T>(), "cannot write random bytes into non-trivially copyable type");
|
||||
typename std::remove_cv<T>::type res;
|
||||
generate_random_bytes_thread_safe(sizeof(T), (uint8_t*)&res);
|
||||
return res;
|
||||
@@ -314,8 +316,14 @@ namespace crypto {
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
/* Do NOT overload the << operator for crypto::secret_key here. Use secret_key_explicit_print_ref
|
||||
* instead to prevent accidental implicit dumping of secret key material to the logs (which has
|
||||
* happened before). For the same reason, do not overload it for crypto::ec_scalar either since
|
||||
* crypto::secret_key is a subclass. I'm not sorry that it's obtuse; that's the point, bozo.
|
||||
*/
|
||||
struct secret_key_explicit_print_ref { const crypto::secret_key &sk; };
|
||||
inline std::ostream &operator <<(std::ostream &o, const secret_key_explicit_print_ref v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(unwrap(unwrap(v.sk)))); return o;
|
||||
}
|
||||
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
|
||||
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
|
||||
@@ -335,8 +343,16 @@ namespace crypto {
|
||||
|
||||
inline bool operator<(const public_key &p1, const public_key &p2) { return memcmp(&p1, &p2, sizeof(public_key)) < 0; }
|
||||
inline bool operator>(const public_key &p1, const public_key &p2) { return p2 < p1; }
|
||||
inline bool operator<(const key_image &p1, const key_image &p2) { return memcmp(&p1, &p2, sizeof(key_image)) < 0; }
|
||||
inline bool operator>(const key_image &p1, const key_image &p2) { return p2 < p1; }
|
||||
}
|
||||
|
||||
// type conversions for easier calls to sc_add(), sc_sub(), hash functions
|
||||
inline unsigned char* to_bytes(crypto::ec_scalar &scalar) { return &reinterpret_cast<unsigned char&>(scalar); }
|
||||
inline const unsigned char* to_bytes(const crypto::ec_scalar &scalar) { return &reinterpret_cast<const unsigned char&>(scalar); }
|
||||
inline unsigned char* to_bytes(crypto::ec_point &point) { return &reinterpret_cast<unsigned char&>(point); }
|
||||
inline const unsigned char* to_bytes(const crypto::ec_point &point) { return &reinterpret_cast<const unsigned char&>(point); }
|
||||
|
||||
CRYPTO_MAKE_HASHABLE(public_key)
|
||||
CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(secret_key)
|
||||
CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(public_key_memsafe)
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sodium/crypto_verify_32.h>
|
||||
|
||||
#define CRYPTO_MAKE_COMPARABLE(type) \
|
||||
@@ -60,14 +61,18 @@ namespace crypto { \
|
||||
namespace crypto { \
|
||||
static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \
|
||||
inline std::size_t hash_value(const type &_v) { \
|
||||
return reinterpret_cast<const std::size_t &>(_v); \
|
||||
std::size_t h; \
|
||||
memcpy(&h, std::addressof(_v), sizeof(h)); \
|
||||
return h; \
|
||||
} \
|
||||
} \
|
||||
namespace std { \
|
||||
template<> \
|
||||
struct hash<crypto::type> { \
|
||||
std::size_t operator()(const crypto::type &_v) const { \
|
||||
return reinterpret_cast<const std::size_t &>(_v); \
|
||||
std::size_t h; \
|
||||
memcpy(&h, std::addressof(_v), sizeof(h)); \
|
||||
return h; \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
@@ -152,6 +152,17 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
m_keys.m_multisig_keys.clear();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_base::set_spend_key(const crypto::secret_key& spend_secret_key)
|
||||
{
|
||||
// make sure derived spend public key matches saved public spend key
|
||||
crypto::public_key spend_public_key;
|
||||
crypto::secret_key_to_public_key(spend_secret_key, spend_public_key);
|
||||
CHECK_AND_ASSERT_THROW_MES(m_keys.m_account_address.m_spend_public_key == spend_public_key,
|
||||
"Unexpected derived public spend key");
|
||||
|
||||
m_keys.m_spend_secret_key = spend_secret_key;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
|
||||
{
|
||||
crypto::secret_key first = generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, recovery_key, recover);
|
||||
|
||||
@@ -95,6 +95,7 @@ namespace cryptonote
|
||||
bool store(const std::string& file_path);
|
||||
|
||||
void forget_spend_key();
|
||||
void set_spend_key(const crypto::secret_key& spend_secret_key);
|
||||
const std::vector<crypto::secret_key> &get_multisig_keys() const { return m_keys.m_multisig_keys; }
|
||||
|
||||
void encrypt_keys(const crypto::chacha_key &key) { m_keys.encrypt(key); }
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "connection_context.h"
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
|
||||
@@ -69,4 +70,23 @@ namespace cryptonote
|
||||
};
|
||||
return std::numeric_limits<size_t>::max();
|
||||
}
|
||||
|
||||
void cryptonote_connection_context::set_state_normal()
|
||||
{
|
||||
m_state = state_normal;
|
||||
m_expected_heights_start = 0;
|
||||
m_needed_objects.clear();
|
||||
m_needed_objects.shrink_to_fit();
|
||||
m_expected_heights.clear();
|
||||
m_expected_heights.shrink_to_fit();
|
||||
m_requested_objects.clear();
|
||||
}
|
||||
|
||||
boost::optional<crypto::hash> cryptonote_connection_context::get_expected_hash(const uint64_t height) const
|
||||
{
|
||||
const auto difference = height - m_expected_heights_start;
|
||||
if (height < m_expected_heights_start || m_expected_heights.size() < difference)
|
||||
return boost::none;
|
||||
return m_expected_heights[difference];
|
||||
}
|
||||
} // cryptonote
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/optional/optional_fwd.hpp>
|
||||
#include "net/net_utils_base.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
@@ -42,7 +43,7 @@ namespace cryptonote
|
||||
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
|
||||
{
|
||||
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
|
||||
m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
|
||||
m_expected_heights_start(0), m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
|
||||
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0),
|
||||
m_expect_response(0), m_expect_height(0), m_num_requested(0) {}
|
||||
|
||||
@@ -92,11 +93,18 @@ namespace cryptonote
|
||||
//! \return Maximum number of bytes permissible for `command`.
|
||||
static size_t get_max_bytes(int command) noexcept;
|
||||
|
||||
//! Use this instead of `m_state = state_normal`.
|
||||
void set_state_normal();
|
||||
|
||||
boost::optional<crypto::hash> get_expected_hash(uint64_t height) const;
|
||||
|
||||
state m_state;
|
||||
std::vector<std::pair<crypto::hash, uint64_t>> m_needed_objects;
|
||||
std::vector<crypto::hash> m_expected_heights;
|
||||
std::unordered_set<crypto::hash> m_requested_objects;
|
||||
uint64_t m_remote_blockchain_height;
|
||||
uint64_t m_last_response_height;
|
||||
uint64_t m_expected_heights_start;
|
||||
boost::posix_time::ptime m_last_request_time;
|
||||
copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
|
||||
crypto::hash m_last_known_hash;
|
||||
|
||||
@@ -200,8 +200,11 @@ namespace cryptonote
|
||||
std::vector<uint8_t> extra;
|
||||
// TX type
|
||||
cryptonote::transaction_type type;
|
||||
// Return address
|
||||
crypto::public_key return_address;
|
||||
// Return address list (must be at least 1 and at most BULLETPROOF_MAX_OUTPUTS-1 - the "-1" is for the change output)
|
||||
std::vector<crypto::public_key> return_address_list;
|
||||
//return_address_change_mask
|
||||
std::vector<uint8_t> return_address_change_mask;
|
||||
// Return TX public key
|
||||
crypto::public_key return_pubkey;
|
||||
// Source asset type
|
||||
@@ -221,11 +224,18 @@ namespace cryptonote
|
||||
FIELD(vout)
|
||||
FIELD(extra)
|
||||
VARINT_FIELD(type)
|
||||
if (type != cryptonote::transaction_type::PROTOCOL) {
|
||||
if (type != cryptonote::transaction_type::UNSET &&
|
||||
type != cryptonote::transaction_type::PROTOCOL) {
|
||||
|
||||
VARINT_FIELD(amount_burnt)
|
||||
if (type != cryptonote::transaction_type::MINER) {
|
||||
FIELD(return_address)
|
||||
FIELD(return_pubkey)
|
||||
if (type == cryptonote::transaction_type::TRANSFER && version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
FIELD(return_address_list)
|
||||
FIELD(return_address_change_mask)
|
||||
} else {
|
||||
FIELD(return_address)
|
||||
FIELD(return_pubkey)
|
||||
}
|
||||
FIELD(source_asset_type)
|
||||
FIELD(destination_asset_type)
|
||||
VARINT_FIELD(amount_slippage_limit)
|
||||
@@ -244,6 +254,8 @@ namespace cryptonote
|
||||
extra.clear();
|
||||
type = cryptonote::transaction_type::UNSET;
|
||||
return_address = crypto::null_pkey;
|
||||
return_address_list.clear();
|
||||
return_address_change_mask.clear();
|
||||
return_pubkey = crypto::null_pkey;
|
||||
source_asset_type.clear();
|
||||
destination_asset_type.clear();
|
||||
@@ -500,6 +512,18 @@ namespace cryptonote
|
||||
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
|
||||
}
|
||||
|
||||
struct audit_block_info {
|
||||
uint64_t block_height;
|
||||
uint64_t locked_coins_this_block;
|
||||
uint64_t locked_coins_tally;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(block_height)
|
||||
VARINT_FIELD(locked_coins_this_block)
|
||||
VARINT_FIELD(locked_coins_tally)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct yield_block_info {
|
||||
uint64_t block_height;
|
||||
uint64_t slippage_total_this_block;
|
||||
|
||||
@@ -70,8 +70,6 @@ namespace cryptonote {
|
||||
{
|
||||
if (version < 2)
|
||||
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1;
|
||||
if (version < 5)
|
||||
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2;
|
||||
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -166,24 +166,7 @@ namespace boost
|
||||
inline void serialize(Archive &a, cryptonote::transaction_prefix &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.vin;
|
||||
a & x.vout;
|
||||
a & x.extra;
|
||||
a & x.type;
|
||||
if (x.type != cryptonote::transaction_type::MINER && x.type != cryptonote::transaction_type::PROTOCOL) {
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
a & x.source_asset_type;
|
||||
a & x.destination_asset_type;
|
||||
a & x.amount_burnt;
|
||||
a & x.amount_slippage_limit;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.unlock_time;
|
||||
a & x.vin;
|
||||
a & x.vout;
|
||||
a & x.extra;
|
||||
@@ -191,8 +174,39 @@ namespace boost
|
||||
if (x.type != cryptonote::transaction_type::PROTOCOL) {
|
||||
a & x.amount_burnt;
|
||||
if (x.type != cryptonote::transaction_type::MINER) {
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
a & x.return_address_list;
|
||||
a & x.return_address_change_mask;
|
||||
} else {
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
}
|
||||
a & x.source_asset_type;
|
||||
a & x.destination_asset_type;
|
||||
a & x.amount_slippage_limit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.unlock_time;
|
||||
a & x.vin;
|
||||
a & x.vout;
|
||||
a & x.extra;
|
||||
a & x.type;
|
||||
if (x.type != cryptonote::transaction_type::PROTOCOL && x.type != cryptonote::transaction_type::UNSET) {
|
||||
a & x.amount_burnt;
|
||||
if (x.type != cryptonote::transaction_type::MINER) {
|
||||
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
|
||||
a & x.return_address_list;
|
||||
a & x.return_address_change_mask;
|
||||
} else {
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
}
|
||||
a & x.source_asset_type;
|
||||
a & x.destination_asset_type;
|
||||
a & x.amount_slippage_limit;
|
||||
@@ -336,6 +350,36 @@ namespace boost
|
||||
a & x.D;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, rct::zk_proof &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.R;
|
||||
a & x.z1;
|
||||
a & x.z2;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, rct::salvium_input_data_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.aR;
|
||||
a & x.i;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, rct::salvium_data_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.salvium_data_type;
|
||||
a & x.pr_proof;
|
||||
a & x.sa_proof;
|
||||
if (x.salvium_data_type == rct::SalviumAudit)
|
||||
{
|
||||
a & x.cz_proof;
|
||||
a & x.input_verification_data;
|
||||
a & x.spend_pubkey;
|
||||
a & x.enc_view_privkey_str;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, rct::ecdhTuple &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
@@ -389,7 +433,7 @@ namespace boost
|
||||
a & x.type;
|
||||
if (x.type == rct::RCTTypeNull)
|
||||
return;
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus)
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumOne)
|
||||
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
|
||||
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
|
||||
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
|
||||
@@ -399,6 +443,12 @@ namespace boost
|
||||
serializeOutPk(a, x.outPk, ver);
|
||||
a & x.txnFee;
|
||||
a & x.p_r;
|
||||
if (x.type == rct::RCTTypeSalviumOne) {
|
||||
a & x.salvium_data;
|
||||
} else if (x.type == rct::RCTTypeFullProofs) {
|
||||
a & x.salvium_data.pr_proof;
|
||||
a & x.salvium_data.sa_proof;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
@@ -424,7 +474,7 @@ namespace boost
|
||||
a & x.type;
|
||||
if (x.type == rct::RCTTypeNull)
|
||||
return;
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus)
|
||||
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumOne)
|
||||
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
|
||||
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
|
||||
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
|
||||
@@ -434,6 +484,12 @@ namespace boost
|
||||
serializeOutPk(a, x.outPk, ver);
|
||||
a & x.txnFee;
|
||||
a & x.p_r;
|
||||
if (x.type == rct::RCTTypeSalviumOne) {
|
||||
a & x.salvium_data;
|
||||
} else if (x.type == rct::RCTTypeFullProofs) {
|
||||
a & x.salvium_data.pr_proof;
|
||||
a & x.salvium_data.sa_proof;
|
||||
}
|
||||
//--------------
|
||||
a & x.p.rangeSigs;
|
||||
if (x.p.rangeSigs.empty())
|
||||
@@ -445,7 +501,7 @@ namespace boost
|
||||
a & x.p.MGs;
|
||||
if (ver >= 1u)
|
||||
a & x.p.CLSAGs;
|
||||
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus)
|
||||
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus || x.type == rct::RCTTypeFullProofs || x.type == rct::RCTTypeSalviumOne)
|
||||
a & x.p.pseudoOuts;
|
||||
}
|
||||
|
||||
@@ -487,5 +543,5 @@ namespace boost
|
||||
}
|
||||
|
||||
BOOST_CLASS_VERSION(rct::rctSigPrunable, 2)
|
||||
BOOST_CLASS_VERSION(rct::rctSig, 2)
|
||||
BOOST_CLASS_VERSION(rct::rctSig, 4)
|
||||
BOOST_CLASS_VERSION(rct::multisig_out, 1)
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace cryptonote
|
||||
uint64_t get_transaction_weight_clawback(const transaction &tx, size_t n_padded_outputs)
|
||||
{
|
||||
const rct::rctSig &rv = tx.rct_signatures;
|
||||
const bool plus = rv.type == rct::RCTTypeBulletproofPlus;
|
||||
const bool plus = (rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs);
|
||||
const uint64_t bp_base = (32 * ((plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
|
||||
const size_t n_outputs = tx.vout.size();
|
||||
if (n_padded_outputs <= 2)
|
||||
@@ -290,13 +290,13 @@ namespace cryptonote
|
||||
return is_v1_tx(blobdata_ref{tx_blob.data(), tx_blob.size()});
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od)
|
||||
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od, rct::salvium_input_data_t& sid)
|
||||
{
|
||||
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
|
||||
bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
|
||||
if (!r)
|
||||
{
|
||||
MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
|
||||
MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", <viewkey>)");
|
||||
memcpy(&recv_derivation, rct::identity().bytes, sizeof(recv_derivation));
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ namespace cryptonote
|
||||
r = hwdev.generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation);
|
||||
if (!r)
|
||||
{
|
||||
MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")");
|
||||
MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", <viewkey>)");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -317,11 +317,13 @@ namespace cryptonote
|
||||
|
||||
boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev);
|
||||
CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address");
|
||||
|
||||
return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev, use_origin_data, od);
|
||||
|
||||
sid.aR = subaddr_recv_info->derivation;
|
||||
sid.i = real_output_index;
|
||||
return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev, use_origin_data, od, sid);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od)
|
||||
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od, rct::salvium_input_data_t& sid)
|
||||
{
|
||||
if (hwdev.compute_key_image(ack, out_key, recv_derivation, real_output_index, received_index, in_ephemeral, ki))
|
||||
{
|
||||
@@ -400,7 +402,7 @@ namespace cryptonote
|
||||
// SRCG: This is a confusing one - for some reason I was using the line below, and it _seemed_ to work...
|
||||
// ... but I think it was luck! the "od.output_index" would only work for the TD_ORIGIN data, of course...
|
||||
//hwdev.derive_subaddress_public_key(out_key, recv_derivation, od.output_index, P_change);
|
||||
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE) {
|
||||
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE || od.tx_type == cryptonote::transaction_type::AUDIT) {
|
||||
hwdev.derive_subaddress_public_key(out_key, recv_derivation, 0, P_change);
|
||||
} else {
|
||||
hwdev.derive_subaddress_public_key(out_key, recv_derivation, real_output_index, P_change);
|
||||
@@ -415,13 +417,20 @@ namespace cryptonote
|
||||
crypto::secret_key sk_spend = crypto::null_skey;
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation_P_change_tx, od.output_index, spend_skey, sk_spend), false, "Failed to derive secret key for P_change");
|
||||
|
||||
// 3.5 Handle subaddresses
|
||||
if (!received_index.is_zero()) {
|
||||
crypto::secret_key scalar_step3;
|
||||
hwdev.sc_secret_add(scalar_step3, sk_spend, subaddr_sk);
|
||||
sk_spend = scalar_step3;
|
||||
}
|
||||
|
||||
// 4. Derive the public key from the secret key for verification purposes
|
||||
crypto::public_key change_pk;
|
||||
CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(sk_spend, change_pk), false, "Failed to derive public key for P_change");
|
||||
CHECK_AND_ASSERT_MES(P_change == change_pk, false, "derived P_change public key does not match P_change");
|
||||
|
||||
// 5. Calculate the secret spend key "x_return"
|
||||
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE) {
|
||||
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE || od.tx_type == cryptonote::transaction_type::AUDIT) {
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, 0, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'");
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, real_output_index, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'");
|
||||
@@ -433,7 +442,11 @@ namespace cryptonote
|
||||
|
||||
// 6. Create the key_image needed to be able to spend the output
|
||||
hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
|
||||
|
||||
|
||||
// Update the SID to have the correct derivation for P_change as well
|
||||
sid.aR_stake = derivation_P_change_tx;
|
||||
sid.i_stake = od.output_index;
|
||||
|
||||
return true;
|
||||
|
||||
} else {
|
||||
@@ -517,7 +530,7 @@ namespace cryptonote
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(tx.pruned, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support non pruned txes");
|
||||
CHECK_AND_ASSERT_MES(tx.version >= 2, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support v1 txes");
|
||||
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus,
|
||||
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs,
|
||||
std::numeric_limits<uint64_t>::max(), "Unsupported rct_signatures type in get_pruned_transaction_weight");
|
||||
CHECK_AND_ASSERT_MES(!tx.vin.empty(), std::numeric_limits<uint64_t>::max(), "empty vin");
|
||||
CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), std::numeric_limits<uint64_t>::max(), "empty vin");
|
||||
@@ -967,8 +980,8 @@ namespace cryptonote
|
||||
switch (asset_type_id) {
|
||||
case 0x53414C00:
|
||||
return "SAL";
|
||||
case 0x56534400:
|
||||
return "VSD";
|
||||
case 0x53414C31:
|
||||
return "SAL1";
|
||||
case 0x4255524E:
|
||||
return "BURN";
|
||||
case 0x00000000:
|
||||
@@ -984,8 +997,8 @@ namespace cryptonote
|
||||
{
|
||||
if (asset_type == "SAL") {
|
||||
return 0x53414C00;
|
||||
} else if (asset_type == "VSD") {
|
||||
return 0x56534400;
|
||||
} else if (asset_type == "SAL1") {
|
||||
return 0x53414C31;
|
||||
} else if (asset_type == "BURN") {
|
||||
return 0x4255524E;
|
||||
} else if (asset_type == "") {
|
||||
@@ -1230,37 +1243,62 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------
|
||||
bool check_output_types(const transaction& tx, const uint8_t hf_version)
|
||||
{
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "audit and stake transactions should have 1 output");
|
||||
}
|
||||
|
||||
for (const auto &o: tx.vout)
|
||||
{
|
||||
if (hf_version > HF_VERSION_VIEW_TAGS)
|
||||
if (hf_version > HF_VERSION_REQUIRE_VIEW_TAGS)
|
||||
{
|
||||
// from v15, require outputs have view tags
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_tagged_key in transaction id=" << get_transaction_hash(tx));
|
||||
<< o.target.type().name() << ", expected txout_to_tagged_key in transaction");
|
||||
}
|
||||
else if (hf_version < HF_VERSION_VIEW_TAGS)
|
||||
{
|
||||
// require outputs to be of type txout_to_key
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_key in transaction id=" << get_transaction_hash(tx));
|
||||
<< o.target.type().name() << ", expected txout_to_key in transaction");
|
||||
}
|
||||
else //(hf_version == HF_VERSION_VIEW_TAGS)
|
||||
else //(hf_version == HF_VERSION_VIEW_TAGS || hf_version == HF_VERSION_VIEW_TAGS+1)
|
||||
{
|
||||
// require outputs be of type txout_to_key OR txout_to_tagged_key
|
||||
// to allow grace period before requiring all to be txout_to_tagged_key
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction id=" << get_transaction_hash(tx));
|
||||
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction");
|
||||
|
||||
// require all outputs in a tx be of the same type
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
|
||||
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
|
||||
<< "expected matching variant types in transaction id=" << get_transaction_hash(tx));
|
||||
<< "expected matching variant types in transaction");
|
||||
}
|
||||
|
||||
// Verify the asset type
|
||||
std::string asset_type;
|
||||
CHECK_AND_ASSERT_MES(cryptonote::get_output_asset_type(o, asset_type), false, "failed to get asset type");
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
if (hf_version < HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
// Prior to the first audit, ONLY SAL was supported
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
} else {
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: This will NOT always be the case - when we add an audit for SALx it'll need to support that as well
|
||||
// The CHANGE for an AUDIT TX must be SAL (and 0 value, and unspendable, and to the origin wallet, and ...)
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
// LAND AHOY!!!
|
||||
} else if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
if (hf_version < HF_VERSION_AUDIT1_PAUSE) {
|
||||
// PROTOCOL TXs are responsible for paying out SAL and SAL1 during the first AUDIT
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1" || asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
|
||||
}
|
||||
} else {
|
||||
// All other TX types must only spend + create SAL1 (MINER, TRANSFER)
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1338,15 +1376,13 @@ namespace cryptonote
|
||||
CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations");
|
||||
if (out_can_be_to_acc(view_tag_opt, additional_derivations[output_index], output_index, &hwdev))
|
||||
{
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: This is NOT going to work for PROTOCOL_TX except where there is only a single output
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
|
||||
// LAND AHOY!!!
|
||||
auto found = subaddresses.find(subaddress_spendkey);
|
||||
if (found != subaddresses.end())
|
||||
return subaddress_receive_info{ found->second, additional_derivations[output_index] };
|
||||
|
||||
// If we get here, odds are that it is a PROTOCOL_TX (rare for other TX types to have additional derivations!)
|
||||
// If we get here, odds are that it is a PROTOCOL_TX
|
||||
if (output_index != 0) {
|
||||
// Try the derivation with a 0 index as an override - CONVERT / YIELD TXs cannot know their index in the PROTOCOL_TX, so they use 0 in all cases
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], 0, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
|
||||
@@ -1724,7 +1760,7 @@ namespace cryptonote
|
||||
blobdata 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));
|
||||
blob.append(tools::get_varint_data(b.tx_hashes.size() + (b.major_version >= HF_VERSION_ENABLE_N_OUTS ? 2 : 1)));
|
||||
return blob;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
@@ -104,8 +104,8 @@ namespace cryptonote
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
|
||||
bool get_tx_fee(const transaction& tx, uint64_t & fee);
|
||||
uint64_t get_tx_fee(const transaction& tx);
|
||||
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od);
|
||||
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od);
|
||||
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od, rct::salvium_input_data_t& sid);
|
||||
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od, rct::salvium_input_data_t& sid);
|
||||
void get_blob_hash(const blobdata& blob, crypto::hash& res);
|
||||
void get_blob_hash(const blobdata_ref& blob, crypto::hash& res);
|
||||
crypto::hash get_blob_hash(const blobdata& blob);
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <boost/math/special_functions/round.hpp>
|
||||
|
||||
#include "int-util.h"
|
||||
#include "crypto/hash.h"
|
||||
@@ -239,6 +240,63 @@ namespace cryptonote {
|
||||
return res.convert_to<difficulty_type>();
|
||||
}
|
||||
|
||||
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
|
||||
|
||||
// LWMA difficulty algorithm
|
||||
// Copyright (c) 2017-2018 Zawy
|
||||
// MIT license http://www.opensource.org/licenses/mit-license.php.
|
||||
// This is an improved version of Tom Harding's (Deger8) "WT-144"
|
||||
// Karbowanec, Masari, Bitcoin Gold, and Bitcoin Cash have contributed.
|
||||
// See https://github.com/zawy12/difficulty-algorithms/issues/3 for other algos.
|
||||
// Do not use "if solvetime < 0 then solvetime = 1" which allows a catastrophic exploit.
|
||||
// T= target_solvetime;
|
||||
// N=45, 55, 70, 90, 120 for T=600, 240, 120, 90, and 60
|
||||
|
||||
const int64_t T = static_cast<int64_t>(target_seconds);
|
||||
size_t N = DIFFICULTY_WINDOW_V2;
|
||||
|
||||
if (timestamps.size() > N) {
|
||||
timestamps.resize(N + 1);
|
||||
cumulative_difficulties.resize(N + 1);
|
||||
}
|
||||
size_t n = timestamps.size();
|
||||
assert(n == cumulative_difficulties.size());
|
||||
assert(n <= DIFFICULTY_WINDOW_V2);
|
||||
// If new coin, just "give away" first 5 blocks at low difficulty
|
||||
if ( n < 6 ) { return 1; }
|
||||
// If height "n" is from 6 to N, then reset N to n-1.
|
||||
else if (n < N+1) { N=n-1; }
|
||||
|
||||
// To get an average solvetime to within +/- ~0.1%, use an adjustment factor.
|
||||
// adjust=0.99 for 90 < N < 130
|
||||
const long double adjust = 0.998;
|
||||
// The divisor k normalizes LWMA.
|
||||
const long double k = N * (N + 1) / 2;
|
||||
|
||||
long double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0);
|
||||
int64_t solveTime(0);
|
||||
uint64_t difficulty(0), next_difficulty(0);
|
||||
|
||||
// Loop through N most recent blocks.
|
||||
for (size_t i = 1; i <= N; i++) {
|
||||
solveTime = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i - 1]);
|
||||
solveTime = std::min<int64_t>((T * 7), std::max<int64_t>(solveTime, (-7 * T)));
|
||||
difficulty = (cumulative_difficulties[i] - cumulative_difficulties[i - 1]).convert_to<uint64_t>();
|
||||
LWMA += (int64_t)(solveTime * i) / k;
|
||||
sum_inverse_D += 1 / static_cast<double>(difficulty);
|
||||
}
|
||||
|
||||
// Keep LWMA sane in case something unforeseen occurs.
|
||||
if (static_cast<int64_t>(boost::math::round(LWMA)) < T / 20)
|
||||
LWMA = static_cast<double>(T / 20);
|
||||
|
||||
harmonic_mean_D = N / sum_inverse_D * adjust;
|
||||
nextDifficulty = harmonic_mean_D * T / LWMA;
|
||||
next_difficulty = static_cast<uint64_t>(nextDifficulty);
|
||||
|
||||
return next_difficulty;
|
||||
}
|
||||
|
||||
std::string hex(difficulty_type v)
|
||||
{
|
||||
static const char chars[] = "0123456789abcdef";
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace cryptonote
|
||||
bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty);
|
||||
bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
|
||||
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
|
||||
|
||||
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
|
||||
|
||||
std::string hex(difficulty_type v);
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace cryptonote
|
||||
bool m_fee_too_low;
|
||||
bool m_too_few_outputs;
|
||||
bool m_tx_extra_too_big;
|
||||
bool m_version_mismatch; // TX version wrong for the currently-active HF version
|
||||
};
|
||||
|
||||
struct block_verification_context
|
||||
|
||||
+53
-7
@@ -31,6 +31,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
@@ -42,7 +43,9 @@
|
||||
#define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000
|
||||
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
|
||||
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
|
||||
#define CURRENT_TRANSACTION_VERSION 2
|
||||
#define CURRENT_TRANSACTION_VERSION 3
|
||||
#define TRANSACTION_VERSION_2_OUTS 2
|
||||
#define TRANSACTION_VERSION_N_OUTS 3
|
||||
#define CURRENT_BLOCK_MAJOR_VERSION 1
|
||||
#define CURRENT_BLOCK_MINOR_VERSION 1
|
||||
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
|
||||
@@ -85,9 +88,11 @@
|
||||
|
||||
#define DIFFICULTY_TARGET_V2 120 // seconds
|
||||
#define DIFFICULTY_TARGET_V1 60 // seconds - before first fork
|
||||
#define DIFFICULTY_WINDOW_V2 70 // blocks
|
||||
#define DIFFICULTY_WINDOW 720 // blocks
|
||||
#define DIFFICULTY_LAG 15 // !!!
|
||||
#define DIFFICULTY_CUT 60 // timestamps to cut after sorting
|
||||
#define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2
|
||||
#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG
|
||||
|
||||
|
||||
@@ -133,6 +138,10 @@
|
||||
|
||||
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT 1000
|
||||
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_TX_COUNT 20000
|
||||
#define DEFAULT_RPC_MAX_CONNECTIONS_PER_PUBLIC_IP 3
|
||||
#define DEFAULT_RPC_MAX_CONNECTIONS_PER_PRIVATE_IP 25
|
||||
#define DEFAULT_RPC_MAX_CONNECTIONS 100
|
||||
#define DEFAULT_RPC_SOFT_LIMIT_SIZE 25 * 1024 * 1024 // 25 MiB
|
||||
#define MAX_RPC_CONTENT_LENGTH 1048576 // 1 MB
|
||||
|
||||
#define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000
|
||||
@@ -173,6 +182,9 @@
|
||||
|
||||
#define THREAD_STACK_SIZE 5 * 1024 * 1024
|
||||
|
||||
#define SECRET_ENCRYPTION_PK_STR "5e860406bf9221dba6409faa6eb8fecd6f34acc4935634e76b64b90bf2b6d6a6"
|
||||
|
||||
|
||||
/*
|
||||
#define HF_VERSION_DYNAMIC_FEE 4
|
||||
#define HF_VERSION_MIN_MIXIN_4 6
|
||||
@@ -212,11 +224,27 @@
|
||||
|
||||
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT 2
|
||||
#define HF_VERSION_2021_SCALING 2
|
||||
#define HF_VERSION_ENABLE_CONVERT 2
|
||||
#define HF_VERSION_ENABLE_ORACLE 2
|
||||
#define HF_VERSION_SLIPPAGE_YIELD 2
|
||||
#define HF_VERSION_ENABLE_N_OUTS 2
|
||||
|
||||
#define TESTNET_VERSION 11
|
||||
#define HF_VERSION_FULL_PROOFS 3
|
||||
|
||||
#define HF_VERSION_ENFORCE_FULL_PROOFS 4
|
||||
|
||||
#define HF_VERSION_SHUTDOWN_USER_TXS 5
|
||||
|
||||
#define HF_VERSION_AUDIT1 6
|
||||
#define HF_VERSION_SALVIUM_ONE_PROOFS 6
|
||||
|
||||
#define HF_VERSION_AUDIT1_PAUSE 7
|
||||
#define HF_VERSION_AUDIT2 8
|
||||
#define HF_VERSION_AUDIT2_PAUSE 9
|
||||
|
||||
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
|
||||
#define HF_VERSION_ENABLE_CONVERT 255
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
#define HF_VERSION_SLIPPAGE_YIELD 255
|
||||
|
||||
#define TESTNET_VERSION 14
|
||||
#define STAGENET_VERSION 1
|
||||
|
||||
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
|
||||
@@ -267,10 +295,15 @@ namespace config
|
||||
|
||||
uint32_t const GENESIS_NONCE = 10000;
|
||||
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = {
|
||||
{HF_VERSION_AUDIT1, {30*24*10, {"SAL", "SAL1"}}},
|
||||
{HF_VERSION_AUDIT2, {30*24*14, {"SAL", "SAL1"}}}
|
||||
};
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
|
||||
|
||||
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
|
||||
|
||||
|
||||
// Hash domain separators
|
||||
const char HASH_KEY_BULLETPROOF_EXPONENT[] = "bulletproof";
|
||||
const char HASH_KEY_BULLETPROOF_PLUS_EXPONENT[] = "bulletproof_plus";
|
||||
@@ -280,6 +313,8 @@ namespace config
|
||||
const unsigned char HASH_KEY_ENCRYPTED_PAYMENT_ID = 0x8d;
|
||||
const unsigned char HASH_KEY_WALLET = 0x8c;
|
||||
const unsigned char HASH_KEY_WALLET_CACHE = 0x8d;
|
||||
const unsigned char HASH_KEY_BACKGROUND_CACHE = 0x8e;
|
||||
const unsigned char HASH_KEY_BACKGROUND_KEYS_FILE = 0x8f;
|
||||
const unsigned char HASH_KEY_RPC_PAYMENT_NONCE = 0x58;
|
||||
const unsigned char HASH_KEY_MEMORY = 'k';
|
||||
const unsigned char HASH_KEY_MULTISIG[] = {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
@@ -340,6 +375,11 @@ namespace config
|
||||
std::string const GENESIS_TX = "020001ff000180c0d0c7bbbff60302838f76f69b70bb0d0f1961a12f6082a033d22285c07d4f12ec93c28197ae2a600353414c3c2101009e8b0abce686c417a1b1344eb7337176bdca90cc928b0facec8a9516190645010000";
|
||||
uint32_t const GENESIS_NONCE = 10001;
|
||||
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = {
|
||||
{HF_VERSION_AUDIT1, {30, {"SAL", "SAL1"}}},
|
||||
{HF_VERSION_AUDIT2, {40, {"SAL", "SAL1"}}},
|
||||
};
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 20;
|
||||
|
||||
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
|
||||
@@ -366,6 +406,8 @@ namespace config
|
||||
std::string const GENESIS_TX = "013c01ff0001ffffffffffff0302df5d56da0c7d643ddd1ce61901c7bdc5fb1738bfe39fbe69c28a3a7032729c0f2101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b";
|
||||
uint32_t const GENESIS_NONCE = 10002;
|
||||
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = { {HF_VERSION_AUDIT1, {30, {"SAL", "SAL1"}}} };
|
||||
|
||||
const uint64_t STAKE_LOCK_PERIOD = 20;
|
||||
|
||||
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
|
||||
@@ -402,7 +444,8 @@ namespace cryptonote
|
||||
uint32_t const GENESIS_NONCE;
|
||||
std::array<std::string, 3> const ORACLE_URLS;
|
||||
std::string const ORACLE_PUBLIC_KEY;
|
||||
uint64_t STAKE_LOCK_PERIOD;
|
||||
uint64_t const STAKE_LOCK_PERIOD;
|
||||
std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> const AUDIT_HARD_FORKS;
|
||||
std::string TREASURY_ADDRESS;
|
||||
};
|
||||
inline const config_t& get_config(network_type nettype)
|
||||
@@ -420,6 +463,7 @@ namespace cryptonote
|
||||
::config::ORACLE_URLS,
|
||||
::config::ORACLE_PUBLIC_KEY,
|
||||
::config::STAKE_LOCK_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::TREASURY_ADDRESS
|
||||
};
|
||||
static const config_t testnet = {
|
||||
@@ -435,6 +479,7 @@ namespace cryptonote
|
||||
::config::testnet::ORACLE_URLS,
|
||||
::config::testnet::ORACLE_PUBLIC_KEY,
|
||||
::config::testnet::STAKE_LOCK_PERIOD,
|
||||
::config::testnet::AUDIT_HARD_FORKS,
|
||||
::config::testnet::TREASURY_ADDRESS
|
||||
};
|
||||
static const config_t stagenet = {
|
||||
@@ -450,6 +495,7 @@ namespace cryptonote
|
||||
::config::stagenet::ORACLE_URLS,
|
||||
::config::stagenet::ORACLE_PUBLIC_KEY,
|
||||
::config::stagenet::STAKE_LOCK_PERIOD,
|
||||
::config::stagenet::AUDIT_HARD_FORKS,
|
||||
::config::stagenet::TREASURY_ADDRESS
|
||||
};
|
||||
switch (nettype)
|
||||
|
||||
+474
-329
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,8 @@
|
||||
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
|
||||
|
||||
#pragma once
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/executor_work_guard.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/function/function_fwd.hpp>
|
||||
#if BOOST_VERSION >= 107400
|
||||
#include <boost/serialization/library_version_type.hpp>
|
||||
@@ -725,6 +726,19 @@ namespace cryptonote
|
||||
*/
|
||||
bool check_tx_outputs(const transaction& tx, tx_verification_context &tvc) const;
|
||||
|
||||
/**
|
||||
* @brief check that a transaction's version & type conforms to current standards
|
||||
*
|
||||
* This function checks, for example at the time of this writing, that
|
||||
* the TX version and type is supported by the current HF version on-chain.
|
||||
*
|
||||
* @param tx the transaction to check the version and type of
|
||||
* @param tvc returned info about tx verification
|
||||
*
|
||||
* @return false if the TX version and/or type is unsupported, otherwise true
|
||||
*/
|
||||
bool check_tx_type_and_version(const transaction& tx, tx_verification_context &tvc) const;
|
||||
|
||||
/**
|
||||
* @brief gets the block weight limit based on recent blocks
|
||||
*
|
||||
@@ -1147,6 +1161,13 @@ namespace cryptonote
|
||||
*/
|
||||
uint64_t get_adjusted_time(uint64_t height) const;
|
||||
|
||||
/**
|
||||
* calculate the audit payouts
|
||||
*
|
||||
* @return TRUE if the payouts were calculated successfully, FALSE otherwise
|
||||
*/
|
||||
bool calculate_audit_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& audit_payouts);
|
||||
|
||||
/**
|
||||
* calculate the yield payouts
|
||||
*
|
||||
@@ -1154,6 +1175,15 @@ namespace cryptonote
|
||||
*/
|
||||
bool calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_payouts);
|
||||
|
||||
/**
|
||||
* @brief get the ABI entry for a particular height from the cache
|
||||
*
|
||||
* Retrieve the ABI entry for the specified height from the local cache.
|
||||
*
|
||||
* @return TRUE if the entry was located and returned, FALSE otherwise
|
||||
*/
|
||||
bool get_abi_entry(const uint64_t height, cryptonote::audit_block_info& ybi);
|
||||
|
||||
/**
|
||||
* @brief get the complete YBI cache
|
||||
*
|
||||
@@ -1251,9 +1281,9 @@ namespace cryptonote
|
||||
crypto::hash m_difficulty_for_next_block_top_hash;
|
||||
difficulty_type m_difficulty_for_next_block;
|
||||
|
||||
boost::asio::io_service m_async_service;
|
||||
boost::asio::io_context m_async_service;
|
||||
boost::thread_group m_async_pool;
|
||||
std::unique_ptr<boost::asio::io_service::work> m_async_work_idle;
|
||||
std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> m_async_work_idle;
|
||||
|
||||
// some invalid blocks
|
||||
blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info
|
||||
@@ -1516,12 +1546,11 @@ namespace cryptonote
|
||||
*
|
||||
* @param b the block containing the miner transaction to be validated
|
||||
* @param height the blockchain's weight
|
||||
* @param txs a vector containing all the TXs and their blobs, needed to obtain tx_types, asset_types and burnt amounts
|
||||
* @param version hard fork version for that transaction
|
||||
*
|
||||
* @return false if anything is found wrong with the protocol transaction, otherwise true
|
||||
*/
|
||||
bool validate_protocol_transaction(const block& b, uint64_t height, std::vector<std::pair<transaction, blobdata>>& txs, uint8_t hf_version);
|
||||
bool validate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version);
|
||||
|
||||
/**
|
||||
* @brief reverts the blockchain to its previous state following a failed switch
|
||||
|
||||
@@ -842,8 +842,8 @@ namespace cryptonote
|
||||
}
|
||||
bad_semantics_txes_lock.unlock();
|
||||
|
||||
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
const size_t max_tx_version = (version < HF_VERSION_SLIPPAGE_YIELD) ? 2 : CURRENT_TRANSACTION_VERSION;
|
||||
uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
const size_t max_tx_version = (hf_version >= HF_VERSION_ENABLE_N_OUTS) ? TRANSACTION_VERSION_N_OUTS : TRANSACTION_VERSION_2_OUTS;
|
||||
if (tx.version == 0 || tx.version > max_tx_version)
|
||||
{
|
||||
// v2 is the latest one we know
|
||||
@@ -923,6 +923,24 @@ namespace cryptonote
|
||||
if (tx_info[n].tx->version < 2)
|
||||
continue;
|
||||
const rct::rctSig &rv = tx_info[n].tx->rct_signatures;
|
||||
const uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) {
|
||||
MERROR_VER("Invalid RCT type provided");
|
||||
set_semantics_failed(tx_info[n].tx_hash);
|
||||
tx_info[n].tvc.m_verifivation_failed = true;
|
||||
tx_info[n].result = false;
|
||||
return false;
|
||||
}
|
||||
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs) {
|
||||
MERROR_VER("Invalid RCT type provided");
|
||||
set_semantics_failed(tx_info[n].tx_hash);
|
||||
tx_info[n].tvc.m_verifivation_failed = true;
|
||||
tx_info[n].result = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
switch (rv.type) {
|
||||
case rct::RCTTypeNull:
|
||||
// coinbase should not come here, so we reject for all other types
|
||||
@@ -936,6 +954,7 @@ namespace cryptonote
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
|
||||
0
|
||||
))
|
||||
{
|
||||
@@ -970,6 +989,8 @@ namespace cryptonote
|
||||
rvv.push_back(&rv); // delayed batch verification
|
||||
break;
|
||||
case rct::RCTTypeBulletproofPlus:
|
||||
case rct::RCTTypeFullProofs:
|
||||
case rct::RCTTypeSalviumOne:
|
||||
if (!is_canonical_bulletproof_plus_layout(rv.p.bulletproofs_plus))
|
||||
{
|
||||
MERROR_VER("Bulletproof_plus does not have canonical form");
|
||||
@@ -996,12 +1017,13 @@ namespace cryptonote
|
||||
{
|
||||
if (!tx_info[n].result)
|
||||
continue;
|
||||
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus)
|
||||
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs && tx_info[n].tx->rct_signatures.type != rct::RCTTypeSalviumOne)
|
||||
continue;
|
||||
if (!rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures,
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
|
||||
0
|
||||
))
|
||||
{
|
||||
|
||||
@@ -46,6 +46,11 @@ using namespace epee;
|
||||
#include "ringct/rctSigs.h"
|
||||
#include "oracle/asset_types.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "crypto/keccak.h"
|
||||
#include "crypto/crypto-ops.h"
|
||||
}
|
||||
using namespace crypto;
|
||||
|
||||
namespace cryptonote
|
||||
@@ -110,7 +115,7 @@ namespace cryptonote
|
||||
CHECK_AND_ASSERT_THROW_MES(tmp == rct::identity(), "invert failed");
|
||||
return inv;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------
|
||||
void classify_addresses(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr, size_t &num_stdaddresses, size_t &num_subaddresses, account_public_address &single_dest_subaddress)
|
||||
{
|
||||
@@ -203,7 +208,7 @@ namespace cryptonote
|
||||
// We are done here - return to caller
|
||||
return true;
|
||||
|
||||
} else if (tx_type == cryptonote::transaction_type::STAKE) {
|
||||
} else if (tx_type == cryptonote::transaction_type::STAKE || tx_type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// CONVERT / YIELD Semantics
|
||||
// From this point forward, we are departing from the original "return address" scheme
|
||||
@@ -254,6 +259,7 @@ namespace cryptonote
|
||||
// Not implemented yet
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
//---------------------------------------------------------------
|
||||
bool get_conversion_rate(const oracle::pricing_record& pr, const std::string& from_asset, const std::string& to_asset, uint64_t& rate) {
|
||||
// Check for burns
|
||||
@@ -327,19 +333,14 @@ namespace cryptonote
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
//---------------------------------------------------------------
|
||||
bool construct_protocol_tx(const size_t height,
|
||||
uint64_t& protocol_fee,
|
||||
transaction& tx,
|
||||
std::vector<protocol_data_entry>& protocol_data,
|
||||
std::map<std::string, uint64_t> circ_supply,
|
||||
const oracle::pricing_record& pr,
|
||||
const account_public_address &miner_address,
|
||||
const account_public_address &treasury_address,
|
||||
const uint8_t hf_version) {
|
||||
|
||||
// A vector to contain all of the additional _tx_secret_keys_
|
||||
//std::vector<crypto::secret_key>& additional_tx_keys;
|
||||
bool construct_protocol_tx(
|
||||
const size_t height,
|
||||
transaction& tx,
|
||||
std::vector<protocol_data_entry>& protocol_data,
|
||||
const uint8_t hf_version
|
||||
) {
|
||||
|
||||
// Clear the TX contents
|
||||
tx.set_null();
|
||||
@@ -353,174 +354,33 @@ namespace cryptonote
|
||||
if (!sort_tx_extra(tx.extra, tx.extra))
|
||||
return false;
|
||||
|
||||
// Update the circulating_supply information, while keeping a count of amount to be created using txin_gen
|
||||
std::map<std::string, uint64_t> txin_gen_totals;
|
||||
uint64_t txin_gen_final = 0;
|
||||
for (auto const& entry: protocol_data) {
|
||||
if (!circ_supply.count(entry.source_asset)) {
|
||||
LOG_ERROR("Circulating supply does not have " << entry.source_asset << " balance - invalid source_asset");
|
||||
return false;
|
||||
}
|
||||
// Deduct the amount_burnt from the circulating_supply balance
|
||||
circ_supply[entry.source_asset] -= entry.amount_burnt;
|
||||
}
|
||||
|
||||
// Calculate the slippage for the output amounts
|
||||
LOG_PRINT_L2("Creating protocol_tx...");
|
||||
uint64_t slippage_total = 0;
|
||||
std::vector<crypto::public_key> additional_tx_public_keys;
|
||||
for (auto const& entry: protocol_data) {
|
||||
if (entry.destination_asset == "BURN") {
|
||||
// BURN TX - no slippage, no money minted - skip
|
||||
continue;
|
||||
}
|
||||
// CONVERT TX
|
||||
/*
|
||||
// Create a secret TX key (= s)
|
||||
crypto::secret_key s = keypair::generate(hw::get_device("default")).sec;
|
||||
//additional_tx_keys.push_back(s);
|
||||
|
||||
// Now add the correct TX public key (= sP_change)
|
||||
// This has to be done using smK() call because of g_k_d() performing a torsion clear
|
||||
crypto::public_key txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(entry.P_change), rct::sk2rct(s)));
|
||||
additional_tx_public_keys.push_back(txkey_pub);
|
||||
|
||||
// Calculate the actual return address, because the field we already have is actually the TX pubkey to use
|
||||
// return address = Hs(syF || i)G + P_change = Hs(saP_change || i)G + P_change
|
||||
// Generate the uniqueness for the input
|
||||
size_t output_index = tx.vout.size();
|
||||
|
||||
// y = Hs(uniqueness)
|
||||
ec_scalar y;
|
||||
CHECK_AND_ASSERT_MES(cryptonote::calculate_uniqueness((cryptonote::transaction_type)(entry.type), entry.input_k_image, height, 0, y), false, "while creating protocol_tx outs: failed to calculate uniqueness");
|
||||
|
||||
rct::key key_y = (rct::key&)(y);
|
||||
rct::key key_F = (rct::key&)(entry.return_address);
|
||||
crypto::public_key syF = rct::rct2pk(rct::scalarmultKey(rct::scalarmultKey(key_F, key_y), rct::sk2rct(s)));
|
||||
crypto::key_derivation derivation_syF = AUTO_VAL_INIT(derivation_syF);
|
||||
std::memcpy(derivation_syF.data, syF.data, sizeof(crypto::key_derivation));
|
||||
|
||||
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
|
||||
bool r = crypto::derive_public_key(derivation_syF, output_index, entry.P_change, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed to derive_public_key(" << derivation_syF << ", " << key_y << ", "<< entry.P_change << ")");
|
||||
|
||||
// Sanity checks
|
||||
crypto::public_key P_change_verify = crypto::null_pkey;
|
||||
r = crypto::derive_subaddress_public_key(out_eph_public_key, derivation_syF, output_index, P_change_verify);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed sanity check calling derive_subaddress_public_key(" << out_eph_public_key << ", " << derivation_syF << ", " << key_y << ", " << P_change_verify << ")");
|
||||
CHECK_AND_ASSERT_MES(entry.P_change == P_change_verify, false, "while creating protocol_tx outs: failed sanity check (keys do not match)");
|
||||
*/
|
||||
/*
|
||||
LOG_ERROR("***************************************************************************************");
|
||||
LOG_ERROR("output_index : " << output_index);
|
||||
LOG_ERROR("P_change : " << entry.P_change);
|
||||
LOG_ERROR("key_y : " << key_y);
|
||||
LOG_ERROR("key_F : " << key_F);
|
||||
LOG_ERROR("s : " << s);
|
||||
LOG_ERROR("der. (syF) : " << derivation_syF);
|
||||
LOG_ERROR("txkey_pub : " << txkey_pub);
|
||||
LOG_ERROR("output_key : " << out_eph_public_key << " (derivation_syF, output_index, P_change)");
|
||||
LOG_ERROR("P_change_ver : " << P_change_verify);
|
||||
LOG_ERROR("***************************************************************************************");
|
||||
*/
|
||||
|
||||
if (entry.type == cryptonote::transaction_type::CONVERT) {
|
||||
|
||||
// Now calculate the slippage, and decide if it is going to be converted or refunded
|
||||
uint64_t amount_slippage = 0, amount_minted = 0;
|
||||
bool ok = cryptonote::calculate_conversion(entry.source_asset, entry.destination_asset, entry.amount_burnt, entry.amount_slippage_limit, amount_minted, amount_slippage, circ_supply, pr, hf_version);
|
||||
if (!ok) {
|
||||
LOG_ERROR("failed to calculate slippage when trying to build protocol_tx");
|
||||
return false;
|
||||
}
|
||||
if (amount_minted == 0) {
|
||||
|
||||
// REFUND
|
||||
LOG_PRINT_L2("Conversion TX refunded - slippage too high");
|
||||
txin_gen_totals[entry.source_asset] += entry.amount_burnt;
|
||||
|
||||
// Create the TX output for this refund
|
||||
tx_out out;
|
||||
//cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
} else {
|
||||
|
||||
// CONVERTED
|
||||
LOG_PRINT_L2("Conversion TX submitted - converted " << print_money(entry.amount_burnt) << " " << entry.source_asset << " to " << print_money(amount_minted) << " " << entry.destination_asset << "(slippage " << print_money(amount_slippage) << ")");
|
||||
txin_gen_totals[entry.destination_asset] += amount_minted;
|
||||
|
||||
// Add the slippage to our total for the block
|
||||
if (entry.source_asset == "SAL") {
|
||||
slippage_total += amount_slippage;
|
||||
} else {
|
||||
// Convert the slippage into a SAL amount so we can pay a proportion to the miner
|
||||
uint64_t conversion_rate = 0, amount_slippage_converted = 0;
|
||||
ok = get_conversion_rate(pr, entry.source_asset, entry.destination_asset, conversion_rate);
|
||||
CHECK_AND_ASSERT_MES(ok, false, "Failed to get conversion rate for miner payout");
|
||||
ok = get_converted_amount(conversion_rate, amount_slippage, amount_slippage_converted);
|
||||
CHECK_AND_ASSERT_MES(ok, false, "Failed to get converted slippage amount for miner payout");
|
||||
slippage_total += amount_slippage_converted;
|
||||
}
|
||||
|
||||
// Create the TX output for this conversion
|
||||
tx_out out;
|
||||
//cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
|
||||
cryptonote::set_tx_out(amount_minted, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
} else if (entry.type == cryptonote::transaction_type::STAKE) {
|
||||
|
||||
if (entry.type == cryptonote::transaction_type::STAKE) {
|
||||
// PAYOUT
|
||||
LOG_PRINT_L2("Yield TX payout submitted " << entry.amount_burnt << entry.source_asset);
|
||||
txin_gen_totals[entry.source_asset] += entry.amount_burnt;
|
||||
|
||||
|
||||
// Create the TX output for this refund
|
||||
tx_out out;
|
||||
//cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
} else if (entry.type == cryptonote::transaction_type::AUDIT) {
|
||||
// PAYOUT
|
||||
LOG_PRINT_L2("Audit TX payout submitted " << entry.amount_burnt << entry.source_asset);
|
||||
|
||||
// Create the TX output for this refund
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add in all of the additional TX pubkeys we need to process the payments
|
||||
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
|
||||
|
||||
if (slippage_total > 0) {
|
||||
|
||||
// Add a payout for the miner
|
||||
uint64_t slippage_miner = slippage_total / 5;
|
||||
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
|
||||
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
|
||||
|
||||
r = crypto::derive_public_key(derivation, tx.vout.size(), miner_address.m_spend_public_key, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
|
||||
|
||||
tx_out out_miner;
|
||||
cryptonote::set_tx_out(slippage_miner, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, false, crypto::view_tag{}, out_miner);
|
||||
tx.vout.push_back(out_miner);
|
||||
|
||||
// Add a payout for the treasury
|
||||
crypto::key_derivation derivation_treasury = AUTO_VAL_INIT(derivation_treasury);
|
||||
crypto::public_key out_eph_public_key_treasury = AUTO_VAL_INIT(out_eph_public_key_treasury);
|
||||
r = crypto::generate_key_derivation(treasury_address.m_view_public_key, txkey.sec, derivation_treasury);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << treasury_address.m_view_public_key << ", " << txkey.sec << ")");
|
||||
|
||||
r = crypto::derive_public_key(derivation_treasury, tx.vout.size(), treasury_address.m_spend_public_key, out_eph_public_key_treasury);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
|
||||
|
||||
uint64_t slippage_treasury = slippage_miner >> 1;
|
||||
tx_out out_treasury;
|
||||
cryptonote::set_tx_out(slippage_treasury, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key_treasury, false, crypto::view_tag{}, out_treasury);
|
||||
tx.vout.push_back(out_treasury);
|
||||
}
|
||||
|
||||
// Create the txin_gen now
|
||||
txin_gen in;
|
||||
in.height = height;
|
||||
@@ -564,7 +424,7 @@ namespace cryptonote
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
|
||||
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{txkey.sec} << ")");
|
||||
|
||||
r = crypto::derive_public_key(derivation, 0, miner_address.m_spend_public_key, out_eph_public_key);
|
||||
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
|
||||
@@ -572,10 +432,10 @@ namespace cryptonote
|
||||
uint64_t amount = block_reward;
|
||||
summary_amounts += amount;
|
||||
|
||||
bool use_view_tags = hard_fork_version >= HF_VERSION_VIEW_TAGS;
|
||||
crypto::view_tag view_tag;
|
||||
if (use_view_tags)
|
||||
crypto::derive_view_tag(derivation, 0, view_tag);
|
||||
bool use_view_tags = hard_fork_version >= HF_VERSION_VIEW_TAGS;
|
||||
crypto::view_tag view_tag;
|
||||
if (use_view_tags)
|
||||
crypto::derive_view_tag(derivation, 0, view_tag);
|
||||
|
||||
// Should we award some of the block reward to the stakers?
|
||||
if (height != 0) {
|
||||
@@ -583,6 +443,14 @@ namespace cryptonote
|
||||
// Different forks take a different proportion of the block_reward for stakers
|
||||
switch (hard_fork_version) {
|
||||
case HF_VERSION_BULLETPROOF_PLUS:
|
||||
case HF_VERSION_ENABLE_N_OUTS:
|
||||
case HF_VERSION_FULL_PROOFS:
|
||||
case HF_VERSION_ENFORCE_FULL_PROOFS:
|
||||
case HF_VERSION_SHUTDOWN_USER_TXS:
|
||||
case HF_VERSION_SALVIUM_ONE_PROOFS:
|
||||
case HF_VERSION_AUDIT1_PAUSE:
|
||||
case HF_VERSION_AUDIT2:
|
||||
case HF_VERSION_AUDIT2_PAUSE:
|
||||
// SRCG: subtract 20% that will be rewarded to staking users
|
||||
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
|
||||
tx.amount_burnt = amount / 5;
|
||||
@@ -593,7 +461,10 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(amount, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
|
||||
std::string asset_type = "SAL";
|
||||
if (hard_fork_version >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
asset_type = "SAL1";
|
||||
cryptonote::set_tx_out(amount, asset_type, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
|
||||
tx.vout.push_back(out);
|
||||
|
||||
} else {
|
||||
@@ -639,6 +510,83 @@ namespace cryptonote
|
||||
return addr.m_view_public_key;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// Encrypt function
|
||||
std::string encrypt_pvk(const crypto::secret_key &pvk, const crypto::public_key &PK) {
|
||||
// Step 1: Generate ephemeral keypair
|
||||
crypto::secret_key ephemeral_sk;
|
||||
crypto::public_key ephemeral_pk;
|
||||
crypto::generate_keys(ephemeral_pk, ephemeral_sk);
|
||||
|
||||
// Step 2: Derive shared secret
|
||||
crypto::ec_scalar shared_secret;
|
||||
crypto::key_derivation derivation;
|
||||
if (!crypto::generate_key_derivation(PK, ephemeral_sk, derivation)) {
|
||||
throw std::runtime_error("Failed to generate key derivation");
|
||||
}
|
||||
crypto::derivation_to_scalar(derivation, 0, shared_secret);
|
||||
|
||||
// Step 3: Symmetric key generation (using Keccak hash)
|
||||
crypto::hash symmetric_key_hash;
|
||||
crypto::cn_fast_hash(&shared_secret, sizeof(shared_secret), symmetric_key_hash);
|
||||
|
||||
// Step 4: Encrypt the data (AES-256-CBC or ChaCha20)
|
||||
std::string ciphertext(sizeof(crypto::secret_key), '\0');
|
||||
crypto::chacha_key symmetric_key;
|
||||
memcpy(&symmetric_key, &symmetric_key_hash, sizeof(symmetric_key));
|
||||
crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>();
|
||||
crypto::chacha20(pvk.data, sizeof(crypto::secret_key), symmetric_key, iv, &ciphertext[0]);
|
||||
|
||||
// Step 5: Package ephemeral_pk and ciphertext together
|
||||
std::string encrypted_data = std::string(reinterpret_cast<char*>(&ephemeral_pk), sizeof(ephemeral_pk)) +
|
||||
std::string(reinterpret_cast<char*>(&iv), sizeof(iv)) +
|
||||
ciphertext;
|
||||
return epee::string_tools::buff_to_hex_nodelimer(encrypted_data);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// Decrypt function
|
||||
bool decrypt_pvk(const std::string &encrypted_data_hex, const crypto::secret_key &SK, crypto::secret_key &pvk) {
|
||||
//std::string decrypt_pvk(const std::string &encrypted_data, const crypto::secret_key &SK) {
|
||||
// Step 1: Extract ephemeral_pk, iv, and ciphertext from encrypted_data
|
||||
std::string encrypted_data;
|
||||
for (size_t i = 0; i < encrypted_data_hex.length(); i += 2) {
|
||||
std::istringstream iss(encrypted_data_hex.substr(i, 2));
|
||||
int byte;
|
||||
iss >> std::hex >> byte;
|
||||
encrypted_data += static_cast<char>(byte);
|
||||
}
|
||||
const char *data_ptr = encrypted_data.data();
|
||||
crypto::public_key ephemeral_pk;
|
||||
memcpy(&ephemeral_pk, data_ptr, sizeof(ephemeral_pk));
|
||||
data_ptr += sizeof(ephemeral_pk);
|
||||
|
||||
crypto::chacha_iv iv;
|
||||
memcpy(&iv, data_ptr, sizeof(iv));
|
||||
data_ptr += sizeof(iv);
|
||||
|
||||
std::string ciphertext(data_ptr, encrypted_data.size() - sizeof(ephemeral_pk) - sizeof(iv));
|
||||
|
||||
// Step 2: Derive shared secret
|
||||
crypto::ec_scalar shared_secret;
|
||||
crypto::key_derivation derivation;
|
||||
if (!crypto::generate_key_derivation(ephemeral_pk, SK, derivation)) {
|
||||
throw std::runtime_error("Failed to generate key derivation");
|
||||
}
|
||||
crypto::derivation_to_scalar(derivation, 0, shared_secret);
|
||||
|
||||
// Step 3: Symmetric key generation (using Keccak hash)
|
||||
crypto::hash symmetric_key_hash;
|
||||
crypto::cn_fast_hash(&shared_secret, sizeof(shared_secret), symmetric_key_hash);
|
||||
|
||||
// Step 4: Decrypt the data
|
||||
std::string plaintext(ciphertext.size(), '\0');
|
||||
crypto::chacha_key symmetric_key;
|
||||
memcpy(&symmetric_key, &symmetric_key_hash, sizeof(symmetric_key));
|
||||
crypto::chacha20(ciphertext.data(), ciphertext.size(), symmetric_key, iv, &plaintext[0]);
|
||||
|
||||
memcpy(pvk.data, &plaintext[0], sizeof(crypto::secret_key));
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags)
|
||||
{
|
||||
hw::device &hwdev = sender_account_keys.get_device();
|
||||
@@ -653,8 +601,11 @@ namespace cryptonote
|
||||
tx.set_null();
|
||||
amount_keys.clear();
|
||||
|
||||
if (hf_version >= HF_VERSION_SLIPPAGE_YIELD) {
|
||||
tx.version = 3;
|
||||
tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
|
||||
|
||||
// Configure the correct TX version for the current HF + TX type
|
||||
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
tx.version = TRANSACTION_VERSION_N_OUTS;
|
||||
} else {
|
||||
tx.version = 2;
|
||||
}
|
||||
@@ -662,8 +613,6 @@ namespace cryptonote
|
||||
tx.extra = extra;
|
||||
crypto::public_key txkey_pub;
|
||||
|
||||
tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
|
||||
|
||||
tx.source_asset_type = source_asset;
|
||||
tx.destination_asset_type = dest_asset;
|
||||
|
||||
@@ -749,6 +698,23 @@ namespace cryptonote
|
||||
};
|
||||
std::vector<input_generation_context_data> in_contexts;
|
||||
|
||||
bool audit = (tx_type == cryptonote::transaction_type::AUDIT);
|
||||
rct::salvium_data_t salvium_data;
|
||||
if (audit) {
|
||||
|
||||
// Generate the encrypted private view key
|
||||
crypto::public_key PK;
|
||||
epee::string_tools::hex_to_pod(SECRET_ENCRYPTION_PK_STR, PK);
|
||||
salvium_data.enc_view_privkey_str = encrypt_pvk(sender_account_keys.m_view_secret_key, PK);
|
||||
|
||||
// And now the rest of the structure
|
||||
salvium_data.salvium_data_type = rct::SalviumAudit;
|
||||
salvium_data.input_verification_data.reserve(sources.size());
|
||||
salvium_data.spend_pubkey = sender_account_keys.m_account_address.m_spend_public_key;
|
||||
|
||||
} else {
|
||||
salvium_data.salvium_data_type = rct::SalviumNormal;
|
||||
}
|
||||
uint64_t summary_inputs_money = 0;
|
||||
//fill inputs
|
||||
int idx = -1;
|
||||
@@ -766,14 +732,26 @@ namespace cryptonote
|
||||
in_contexts.push_back(input_generation_context_data());
|
||||
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
|
||||
crypto::key_image img;
|
||||
rct::salvium_input_data_t sid;
|
||||
const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
|
||||
bool use_origin_data = (src_entr.origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
|
||||
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev, use_origin_data, src_entr.origin_tx_data))
|
||||
sid.origin_tx_type = src_entr.origin_tx_data.tx_type;
|
||||
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev, use_origin_data, src_entr.origin_tx_data, sid))
|
||||
{
|
||||
LOG_ERROR("Key image generation failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// SRCG: store the audit data for the source here
|
||||
if (audit) {
|
||||
sid.amount = src_entr.amount;
|
||||
if (sid.origin_tx_type == cryptonote::transaction_type::STAKE) {
|
||||
// STAKE TXs have to use "output_index 0" because they don't know what the actual output_index value will be ahead of time
|
||||
sid.i = 0;
|
||||
}
|
||||
salvium_data.input_verification_data.push_back(sid);
|
||||
}
|
||||
|
||||
//check that derivated key is equal with real output key
|
||||
if(!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) )
|
||||
{
|
||||
@@ -799,6 +777,14 @@ namespace cryptonote
|
||||
tx.vin.push_back(input_to_key);
|
||||
}
|
||||
|
||||
// Sanity check the size of the verification data
|
||||
if (audit) {
|
||||
if (salvium_data.input_verification_data.size() != sources.size()) {
|
||||
LOG_ERROR("Missing input verification data");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shuffle_outs)
|
||||
{
|
||||
std::shuffle(destinations.begin(), destinations.end(), crypto::random_device{});
|
||||
@@ -817,6 +803,7 @@ namespace cryptonote
|
||||
std::swap(tx.vin[i0], tx.vin[i1]);
|
||||
std::swap(in_contexts[i0], in_contexts[i1]);
|
||||
std::swap(sources[i0], sources[i1]);
|
||||
if (audit) std::swap(salvium_data.input_verification_data[i0], salvium_data.input_verification_data[i1]);
|
||||
});
|
||||
|
||||
// figure out if we need to make additional tx pubkeys
|
||||
@@ -849,7 +836,10 @@ namespace cryptonote
|
||||
uint64_t summary_outs_money = 0;
|
||||
//fill outputs
|
||||
size_t output_index = 0;
|
||||
size_t change_index = 0;
|
||||
crypto::secret_key x_change = crypto::null_skey;
|
||||
rct::key key_yF;
|
||||
uint8_t change_index = 0;
|
||||
bool found_change = false;
|
||||
for(const tx_destination_entry& dst_entr: destinations)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount);
|
||||
@@ -870,17 +860,25 @@ namespace cryptonote
|
||||
tx.amount_burnt += dst_entr.amount;
|
||||
continue;
|
||||
}
|
||||
} else if (tx_type == cryptonote::transaction_type::AUDIT) {
|
||||
// Do not create outputs that are staked for yield - discard them as unused
|
||||
if (!dst_entr.is_change) {
|
||||
tx.amount_burnt += dst_entr.amount;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check to see if this is the change output
|
||||
if (dst_entr.is_change) {
|
||||
CHECK_AND_ASSERT_MES(!found_change, false, "Too many change outputs!!!");
|
||||
change_index = output_index;
|
||||
found_change = true;
|
||||
}
|
||||
|
||||
LOG_ERROR("*****************************************************************************");
|
||||
LOG_ERROR("in construct_tx_With_tx_key()");
|
||||
LOG_ERROR("TX type : TRANSFER");
|
||||
LOG_ERROR("tx_key : " << tx_key);
|
||||
LOG_ERROR("tx_key : " << crypto::secret_key_explicit_print_ref{tx_key});
|
||||
LOG_ERROR("tx_pubkey : " << txkey_pub);
|
||||
LOG_ERROR("P_change : " << dst_entr.addr.m_spend_public_key);
|
||||
LOG_ERROR("aP_change : " << dst_entr.addr.m_view_public_key);
|
||||
@@ -902,14 +900,93 @@ namespace cryptonote
|
||||
|
||||
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys));
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
if (hf_version >= HF_VERSION_FULL_PROOFS) {
|
||||
|
||||
// Get the secret spend key for the change element
|
||||
crypto::secret_key spend_skey = crypto::null_skey;
|
||||
if (sender_account_keys.m_multisig_keys.empty())
|
||||
{
|
||||
// if not multisig, use normal spend skey
|
||||
spend_skey = sender_account_keys.m_spend_secret_key;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if multisig, use sum of multisig privkeys (local account's share of aggregate spend key)
|
||||
for (const auto &multisig_key : sender_account_keys.m_multisig_keys)
|
||||
{
|
||||
sc_add((unsigned char*)spend_skey.data,
|
||||
(const unsigned char*)multisig_key.data,
|
||||
(const unsigned char*)spend_skey.data);
|
||||
}
|
||||
}
|
||||
|
||||
// Obtain a separate key_derivation for the P_change output
|
||||
// (using the TX public key and the sender's private view key)
|
||||
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
|
||||
CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation), false, "Failed to generate key_derivation for P_change");
|
||||
|
||||
// Calculate the secret spend key "x_change" for the P_change output
|
||||
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation, change_index, spend_skey, x_change), false, "Failed to derive secret key for P_change");
|
||||
}
|
||||
|
||||
// Get the output public key for the change output
|
||||
crypto::public_key P_change = crypto::null_pkey;
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() >= 2, false, "Internal error - too few outputs for TRANSFER tx");
|
||||
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
|
||||
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
|
||||
|
||||
// Calculate the F points and change mask for every destination
|
||||
for (size_t op_index=0; op_index<tx.vout.size(); ++op_index) {
|
||||
|
||||
// Calculate the y value for return_payment support
|
||||
ec_scalar y;
|
||||
struct {
|
||||
char domain_separator[8];
|
||||
rct::key amount_key;
|
||||
} buf;
|
||||
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
|
||||
std::strncpy(buf.domain_separator, "RETURN", 7);
|
||||
buf.amount_key = amount_keys[op_index];
|
||||
crypto::hash_to_scalar(&buf, sizeof(buf), y);
|
||||
|
||||
// Now generate the return address (and TX pubkey, although we will discard that)
|
||||
crypto::public_key F = crypto::null_pkey;
|
||||
crypto::public_key F_txpubkey = crypto::null_pkey;
|
||||
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, y, sender_account_keys, P_change, additional_tx_public_keys[op_index], F, F_txpubkey, hwdev), false, "Failed to get return_address");
|
||||
|
||||
// Push the F point into the TX vector of F points
|
||||
tx.return_address_list.push_back(F);
|
||||
|
||||
// Calculate the shared secret yF
|
||||
if (hf_version >= HF_VERSION_FULL_PROOFS) {
|
||||
rct::key key_aP = rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(sender_account_keys.m_view_secret_key));
|
||||
key_yF = rct::hash_to_scalar(key_aP);
|
||||
}
|
||||
|
||||
// Calculate the encrypted_change_index data for this output
|
||||
struct {
|
||||
char domain_separator[8];
|
||||
rct::key amount_key;
|
||||
} eci_buf;
|
||||
std::memset(eci_buf.domain_separator, 0x0, sizeof(buf.domain_separator));
|
||||
std::strncpy(eci_buf.domain_separator, "CHG_IDX", 8);
|
||||
eci_buf.amount_key = amount_keys[op_index];
|
||||
crypto::secret_key eci_out;
|
||||
keccak((uint8_t *)&eci_buf, sizeof(eci_buf), (uint8_t*)&eci_out, sizeof(eci_out));
|
||||
uint8_t eci_data = change_index ^ eci_out.data[0];
|
||||
tx.return_address_change_mask.push_back(eci_data);
|
||||
}
|
||||
|
||||
} else if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// Get the output public key for the change output
|
||||
crypto::public_key P_change = crypto::null_pkey;
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER)
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 2, false, "Internal error - incorrect number of outputs (!=2) for TRANSFER tx");
|
||||
else if (tx.type == cryptonote::transaction_type::STAKE)
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for YIELD tx");
|
||||
else if (tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT)
|
||||
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for STAKE/AUDIT tx");
|
||||
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
|
||||
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
|
||||
|
||||
@@ -987,7 +1064,7 @@ namespace cryptonote
|
||||
crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
|
||||
ss_ring_s << "signatures:" << ENDL;
|
||||
std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;});
|
||||
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
|
||||
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << crypto::secret_key_explicit_print_ref{in_contexts[i].in_ephemeral.sec} << ENDL << "real_output: " << src_entr.real_output << ENDL;
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -1097,31 +1174,11 @@ namespace cryptonote
|
||||
fee = summary_inputs_money - summary_outs_money - tx.amount_burnt;
|
||||
|
||||
// zero out all amounts to mask rct outputs, real amounts are now encrypted
|
||||
for (size_t i = 0; i < tx.vin.size(); ++i)
|
||||
{
|
||||
for (size_t i = 0; i < tx.vin.size(); ++i) {
|
||||
if (sources[i].rct)
|
||||
boost::get<txin_to_key>(tx.vin[i]).amount = 0;
|
||||
}
|
||||
std::vector<bool> zero_masks;
|
||||
zero_masks.reserve(tx.vout.size());
|
||||
}
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i) {
|
||||
if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
uint64_t unlock_time = 0;
|
||||
bool ok = get_output_unlock_time(tx.vout[i], unlock_time);
|
||||
if (!ok) {
|
||||
LOG_ERROR("failed to get output asset type for tx.vout[" << i << "]");
|
||||
return false;
|
||||
}
|
||||
if (unlock_time == 0) {
|
||||
zero_masks.emplace_back(false);
|
||||
} else {
|
||||
zero_masks.emplace_back(true);
|
||||
}
|
||||
} else {
|
||||
zero_masks.emplace_back(false);
|
||||
}
|
||||
|
||||
// Clear the amount in the output
|
||||
tx.vout[i].amount = 0;
|
||||
}
|
||||
|
||||
@@ -1130,23 +1187,26 @@ namespace cryptonote
|
||||
rct::ctkeyV outSk;
|
||||
if (use_simple_rct)
|
||||
tx.rct_signatures = rct::genRctSimple(
|
||||
rct::hash2rct(tx_prefix_hash),
|
||||
inSk,
|
||||
destinations,
|
||||
tx_type,
|
||||
source_asset,
|
||||
destination_asset_types,
|
||||
zero_masks,
|
||||
inamounts,
|
||||
outamounts,
|
||||
fee,
|
||||
mixRing,
|
||||
amount_keys,
|
||||
index,
|
||||
outSk,
|
||||
rct_config,
|
||||
hwdev
|
||||
);
|
||||
rct::hash2rct(tx_prefix_hash),
|
||||
inSk,
|
||||
destinations,
|
||||
tx_type,
|
||||
source_asset,
|
||||
destination_asset_types,
|
||||
inamounts,
|
||||
outamounts,
|
||||
fee,
|
||||
mixRing,
|
||||
amount_keys,
|
||||
index,
|
||||
outSk,
|
||||
rct_config,
|
||||
hwdev,
|
||||
salvium_data,
|
||||
rct::sk2rct(x_change),
|
||||
change_index,
|
||||
key_yF
|
||||
);
|
||||
else
|
||||
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption
|
||||
memwipe(inSk.data(), inSk.size() * sizeof(rct::ctkey));
|
||||
|
||||
@@ -39,9 +39,11 @@
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
/*
|
||||
bool get_conversion_rate(const oracle::pricing_record& pr, const std::string& from_asset, const std::string& to_asset, uint64_t& rate);
|
||||
bool get_converted_amount(const uint64_t& conversion_rate, const uint64_t& source_amount, uint64_t& dest_amount);
|
||||
bool calculate_conversion(const std::string& source_asset, const std::string& dest_asset, const uint64_t amount_burnt, const uint64_t amount_slippage_limit, uint64_t& amount_minted, uint64_t& amount_slippage, const std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const uint8_t hf_version);
|
||||
*/
|
||||
//---------------------------------------------------------------
|
||||
/**
|
||||
* Construct the protocol_tx
|
||||
@@ -64,10 +66,11 @@ namespace cryptonote
|
||||
uint8_t type;
|
||||
crypto::public_key P_change;
|
||||
crypto::public_key return_pubkey;
|
||||
uint64_t origin_height;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool construct_protocol_tx(const size_t height, uint64_t& protocol_fee, transaction& tx, std::vector<protocol_data_entry>& protocol_data, std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const account_public_address &miner_address, const account_public_address &treasury_address, const uint8_t hf_version);
|
||||
bool construct_protocol_tx(const size_t height, transaction& tx, std::vector<protocol_data_entry>& protocol_data, const uint8_t hf_version);
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
|
||||
|
||||
@@ -150,6 +153,7 @@ namespace cryptonote
|
||||
FIELD(original)
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(addr)
|
||||
FIELD(asset_type)
|
||||
FIELD(is_subaddress)
|
||||
FIELD(is_integrated)
|
||||
FIELD(is_change)
|
||||
@@ -170,6 +174,9 @@ namespace cryptonote
|
||||
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
|
||||
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& asset_type, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time);
|
||||
|
||||
std::string encrypt_pvk(const crypto::secret_key &pvk, const crypto::public_key &PK);
|
||||
bool decrypt_pvk(const std::string &encrypted_data, const crypto::secret_key &SK, crypto::secret_key &pvk);
|
||||
|
||||
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false);
|
||||
|
||||
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false);
|
||||
|
||||
@@ -112,8 +112,8 @@ namespace cryptonote
|
||||
|
||||
uint64_t get_transaction_weight_limit(uint8_t version)
|
||||
{
|
||||
// from v8, limit a tx to 50% of the minimum block weight
|
||||
if (version >= 8)
|
||||
// from v2, limit a tx to 50% of the minimum block weight
|
||||
if (version >= 2)
|
||||
return get_min_block_weight(version) / 2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
else
|
||||
return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
@@ -167,6 +167,15 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject ALL TXs except miner + protocol for v5
|
||||
if (version == HF_VERSION_SHUTDOWN_USER_TXS) {
|
||||
if (tx.type != cryptonote::transaction_type::MINER && tx.type != cryptonote::transaction_type::PROTOCOL) {
|
||||
LOG_PRINT_L1("User TXs are not permitted for v" + std::to_string(HF_VERSION_SHUTDOWN_USER_TXS));
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!check_inputs_types_supported(tx))
|
||||
{
|
||||
tvc.m_verifivation_failed = true;
|
||||
@@ -259,10 +268,10 @@ namespace cryptonote
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Check the TX type
|
||||
if (tx.type <= cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) {
|
||||
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid type " << (uint8_t)tx.type);
|
||||
if (!m_blockchain.check_tx_type_and_version(tx, tvc)) {
|
||||
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid type " << (uint8_t)tx.type << " and/or version " << tx.version);
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
@@ -1614,7 +1623,7 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------
|
||||
//TODO: investigate whether boolean return is appropriate
|
||||
bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version, oracle::pricing_record& pr, std::map<std::string, uint64_t>& circ_supply, std::vector<txpool_tx_meta_t>& protocol_metadata)
|
||||
bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
@@ -1653,6 +1662,12 @@ namespace cryptonote
|
||||
continue;
|
||||
}
|
||||
|
||||
// SRCG: skip all user TXs for HF 5 - when the node restarts, it'll discard them fully in `tx_memory_pool::validate()`
|
||||
if (version == HF_VERSION_SHUTDOWN_USER_TXS) {
|
||||
LOG_PRINT_L2(" User TXs forbidden by consensus for HF 5 - skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method());
|
||||
|
||||
if (!meta.matches(relay_category::legacy) && !(m_mine_stem_txes && meta.get_relay_method() == relay_method::stem))
|
||||
@@ -1744,14 +1759,6 @@ namespace cryptonote
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check what the TX type is - only CONVERT needs a cash_value
|
||||
if (meta.source_asset_id == meta.destination_asset_id) {
|
||||
// TRANSFER
|
||||
} else {
|
||||
// BURN OR CONVERT (both require inclusion in the protocol_tx calculation for circ_supply purposes)
|
||||
protocol_metadata.push_back(meta);
|
||||
}
|
||||
|
||||
bl.tx_hashes.push_back(sorted_it->second);
|
||||
total_weight += meta.weight;
|
||||
fee += meta.fee;
|
||||
|
||||
@@ -227,13 +227,10 @@ namespace cryptonote
|
||||
* @param fee return-by-reference the total of fees from the included transactions
|
||||
* @param expected_reward return-by-reference the total reward awarded to the miner finding this block, including transaction fees
|
||||
* @param version hard fork version to use for consensus rules
|
||||
* @param pr the current pricing record
|
||||
* @param circ_cupply the circulating supply information for all asset types
|
||||
* @param protocol_metadata the TX-specific data needed to create conversion outputs in the protocol TX (including converted amounts and refunds)
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version, oracle::pricing_record& pr, std::map<std::string, uint64_t>& circ_supply, std::vector<txpool_tx_meta_t>& protocol_metadata);
|
||||
bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version);
|
||||
|
||||
/**
|
||||
* @brief get a list of all transactions in the pool
|
||||
|
||||
@@ -130,7 +130,7 @@ bool ver_rct_non_semantics_simple_cached
|
||||
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions
|
||||
// holds true in the future, enable the verification hash by modifying the `untested_tx`
|
||||
// condition below.
|
||||
const bool untested_tx = tx.version > 2 || tx.rct_signatures.type > rct::RCTTypeBulletproofPlus;
|
||||
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeSalviumOne;
|
||||
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
|
||||
|
||||
// Don't cache older (or newer) rctSig types
|
||||
|
||||
@@ -40,15 +40,6 @@
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "cn.block_queue"
|
||||
|
||||
namespace std {
|
||||
static_assert(sizeof(size_t) <= sizeof(boost::uuids::uuid), "boost::uuids::uuid too small");
|
||||
template<> struct hash<boost::uuids::uuid> {
|
||||
std::size_t operator()(const boost::uuids::uuid &_v) const {
|
||||
return reinterpret_cast<const std::size_t &>(_v);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
|
||||
@@ -60,10 +51,10 @@ void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_comp
|
||||
blocks.insert(span(height, std::move(bcel), connection_id, addr, rate, size));
|
||||
if (has_hashes)
|
||||
{
|
||||
for (const crypto::hash &h: hashes)
|
||||
for (std::size_t i = 0; i < hashes.size(); ++i)
|
||||
{
|
||||
requested_hashes.insert(h);
|
||||
have_blocks.insert(h);
|
||||
requested_hashes.insert(hashes[i]);
|
||||
have_blocks.emplace(hashes[i], height + i);
|
||||
}
|
||||
set_span_hashes(height, connection_id, hashes);
|
||||
}
|
||||
@@ -228,6 +219,16 @@ bool block_queue::have(const crypto::hash &hash) const
|
||||
return have_blocks.find(hash) != have_blocks.end();
|
||||
}
|
||||
|
||||
std::uint64_t block_queue::have_height(const crypto::hash &hash) const
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
const auto elem = have_blocks.find(hash);
|
||||
if (elem == have_blocks.end())
|
||||
return std::numeric_limits<std::uint64_t>::max();
|
||||
return elem->second;
|
||||
}
|
||||
|
||||
|
||||
std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
@@ -472,7 +473,7 @@ bool block_queue::has_spans(const boost::uuids::uuid &connection_id) const
|
||||
float block_queue::get_speed(const boost::uuids::uuid &connection_id) const
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> lock(mutex);
|
||||
std::unordered_map<boost::uuids::uuid, float> speeds;
|
||||
std::unordered_map<boost::uuids::uuid, float, boost::hash<boost::uuids::uuid>> speeds;
|
||||
for (const auto &span: blocks)
|
||||
{
|
||||
if (span.blocks.empty())
|
||||
@@ -480,7 +481,7 @@ float block_queue::get_speed(const boost::uuids::uuid &connection_id) const
|
||||
// note that the average below does not average over the whole set, but over the
|
||||
// previous pseudo average and the latest rate: this gives much more importance
|
||||
// to the latest measurements, which is fine here
|
||||
std::unordered_map<boost::uuids::uuid, float>::iterator i = speeds.find(span.connection_id);
|
||||
const auto i = speeds.find(span.connection_id);
|
||||
if (i == speeds.end())
|
||||
speeds.insert(std::make_pair(span.connection_id, span.rate));
|
||||
else
|
||||
|
||||
@@ -98,6 +98,7 @@ namespace cryptonote
|
||||
bool foreach(std::function<bool(const span&)> f) const;
|
||||
bool requested(const crypto::hash &hash) const;
|
||||
bool have(const crypto::hash &hash) const;
|
||||
std::uint64_t have_height(const crypto::hash &hash) const;
|
||||
|
||||
private:
|
||||
void erase_block(block_map::iterator j);
|
||||
@@ -107,6 +108,6 @@ namespace cryptonote
|
||||
block_map blocks;
|
||||
mutable boost::recursive_mutex mutex;
|
||||
std::unordered_set<crypto::hash> requested_hashes;
|
||||
std::unordered_set<crypto::hash> have_blocks;
|
||||
std::unordered_map<crypto::hash, std::uint64_t> have_blocks;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -158,6 +158,7 @@ namespace cryptonote
|
||||
bool should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const;
|
||||
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
|
||||
void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans);
|
||||
void drop_connection(const boost::uuids::uuid&);
|
||||
void drop_connections(const epee::net_utils::network_address address);
|
||||
bool kick_idle_peers();
|
||||
bool check_standby_peers();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
// (may contain code and/or modifications by other developers)
|
||||
// developer rfree: this code is caller of our new network code, and is modded; e.g. for rate limiting
|
||||
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <list>
|
||||
#include <ctime>
|
||||
|
||||
@@ -380,7 +381,7 @@ namespace cryptonote
|
||||
|
||||
if(m_core.have_block(hshd.top_id))
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
if(is_inital && hshd.current_height >= target && target == m_core.get_current_blockchain_height())
|
||||
on_connection_synchronized();
|
||||
return true;
|
||||
@@ -389,7 +390,7 @@ namespace cryptonote
|
||||
// No chain synchronization over hidden networks (tor, i2p, etc.)
|
||||
if(context.m_remote_address.get_zone() != epee::net_utils::zone::public_)
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -430,7 +431,7 @@ namespace cryptonote
|
||||
|
||||
if (m_no_sync)
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1198,8 +1199,9 @@ namespace cryptonote
|
||||
block_hashes.reserve(arg.blocks.size());
|
||||
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
|
||||
uint64_t start_height = std::numeric_limits<uint64_t>::max();
|
||||
crypto::hash previous{};
|
||||
cryptonote::block b;
|
||||
for(const block_complete_entry& block_entry: arg.blocks)
|
||||
for(std::size_t i = 0; i < arg.blocks.size(); ++i)
|
||||
{
|
||||
if (m_stopping)
|
||||
{
|
||||
@@ -1207,10 +1209,10 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
crypto::hash block_hash;
|
||||
if(!parse_and_validate_block_from_blob(block_entry.block, b, block_hash))
|
||||
if(!parse_and_validate_block_from_blob(arg.blocks[i].block, b, block_hash))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
@@ -1218,14 +1220,25 @@ namespace cryptonote
|
||||
if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong block: block: miner tx does not have exactly one txin_gen input"
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
|
||||
<< epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto this_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
|
||||
if (context.get_expected_hash(this_height) != block_hash)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Sent invalid chain");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// if first block
|
||||
if (start_height == std::numeric_limits<uint64_t>::max())
|
||||
{
|
||||
start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
|
||||
start_height = this_height;
|
||||
if (start_height > context.m_expect_height)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection");
|
||||
@@ -1233,21 +1246,45 @@ namespace cryptonote
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (this_height == 0 || context.get_expected_hash(this_height - 1) != b.prev_id)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Sent invalid chain");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (b.prev_id != previous)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Sent invalid chain");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
previous = block_hash;
|
||||
|
||||
if (start_height + i != this_height)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("Sent invalid chain");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto req_it = context.m_requested_objects.find(block_hash);
|
||||
if(req_it == context.m_requested_objects.end())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block))
|
||||
<< " wasn't requested, dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
}
|
||||
if(b.tx_hashes.size() != block_entry.txs.size())
|
||||
if(b.tx_hashes.size() != arg.blocks[i].txs.size())
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
|
||||
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection");
|
||||
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block))
|
||||
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << arg.blocks[i].txs.size() << ", dropping connection");
|
||||
drop_connection(context, false, false);
|
||||
++m_sync_bad_spans_downloaded;
|
||||
return 1;
|
||||
@@ -1465,6 +1502,14 @@ namespace cryptonote
|
||||
bool parent_known = m_core.have_block(new_block.prev_id);
|
||||
if (!parent_known)
|
||||
{
|
||||
const std::uint64_t confirmed_height = m_block_queue.have_height(new_block.prev_id);
|
||||
if (confirmed_height != std::numeric_limits<std::uint64_t>::max() && confirmed_height + 1 != start_height)
|
||||
{
|
||||
MERROR(context << "Found incorrect height for " << new_block.prev_id << " provided by " << span_connection_id);
|
||||
drop_connection(span_connection_id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// it could be:
|
||||
// - later in the current chain
|
||||
// - later in an alt chain
|
||||
@@ -2093,7 +2138,6 @@ skip:
|
||||
m_block_queue.flush_stale_spans(live_connections);
|
||||
|
||||
// if we don't need to get next span, and the block queue is full enough, wait a bit
|
||||
bool start_from_current_chain = false;
|
||||
if (!force_next_span)
|
||||
{
|
||||
do
|
||||
@@ -2116,7 +2160,7 @@ skip:
|
||||
return false;
|
||||
}
|
||||
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
|
||||
on_connection_synchronized();
|
||||
return true;
|
||||
@@ -2265,7 +2309,7 @@ skip:
|
||||
return false;
|
||||
}
|
||||
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
|
||||
on_connection_synchronized();
|
||||
return true;
|
||||
@@ -2378,7 +2422,7 @@ skip:
|
||||
const uint64_t blockchain_height = m_core.get_current_blockchain_height();
|
||||
if (std::max(blockchain_height, m_block_queue.get_next_needed_height(blockchain_height)) >= m_core.get_target_blockchain_height())
|
||||
{
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
MLOG_PEER_STATE("Nothing to do for now, switching to normal state");
|
||||
return true;
|
||||
}
|
||||
@@ -2421,14 +2465,11 @@ skip:
|
||||
m_core.get_short_chain_history(r.block_ids);
|
||||
CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
|
||||
|
||||
if (!start_from_current_chain)
|
||||
// we'll want to start off from where we are on that peer, which may not be added yet
|
||||
if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
|
||||
{
|
||||
// we'll want to start off from where we are on that peer, which may not be added yet
|
||||
if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
|
||||
{
|
||||
context.m_expect_height = std::numeric_limits<uint64_t>::max();
|
||||
r.block_ids.push_front(context.m_last_known_hash);
|
||||
}
|
||||
context.m_expect_height = std::numeric_limits<uint64_t>::max();
|
||||
r.block_ids.push_front(context.m_last_known_hash);
|
||||
}
|
||||
|
||||
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
|
||||
@@ -2441,7 +2482,7 @@ skip:
|
||||
|
||||
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
|
||||
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
|
||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() << ", start_from_current_chain " << start_from_current_chain);
|
||||
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size());
|
||||
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
|
||||
MLOG_PEER_STATE("requesting chain");
|
||||
}else
|
||||
@@ -2455,7 +2496,7 @@ skip:
|
||||
<< "\r\nm_requested_objects.size()=" << context.m_requested_objects.size()
|
||||
<< "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]");
|
||||
|
||||
context.m_state = cryptonote_connection_context::state_normal;
|
||||
context.set_state_normal();
|
||||
if (context.m_remote_blockchain_height >= m_core.get_target_blockchain_height())
|
||||
{
|
||||
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
|
||||
@@ -2628,11 +2669,14 @@ skip:
|
||||
return 1;
|
||||
}
|
||||
|
||||
context.m_expected_heights_start = arg.start_height;
|
||||
|
||||
context.m_expected_heights.clear();
|
||||
context.m_expected_heights.reserve(arg.m_block_ids.size());
|
||||
context.m_needed_objects.clear();
|
||||
context.m_needed_objects.reserve(arg.m_block_ids.size());
|
||||
uint64_t added = 0;
|
||||
std::unordered_set<crypto::hash> blocks_found;
|
||||
bool first = true;
|
||||
bool expect_unknown = false;
|
||||
for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
|
||||
{
|
||||
@@ -2644,9 +2688,10 @@ skip:
|
||||
}
|
||||
int where;
|
||||
const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where);
|
||||
if (first)
|
||||
if (i == 0)
|
||||
{
|
||||
if (!have_block && !m_block_queue.requested(arg.m_block_ids[i]) && !m_block_queue.have(arg.m_block_ids[i]))
|
||||
// our outgoing chainlist only has proven blocks (i.e. downloaded)
|
||||
if (!have_block && m_block_queue.have_height(arg.m_block_ids[i]) != arg.start_height)
|
||||
{
|
||||
LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection");
|
||||
drop_connection_with_score(context, 5, false);
|
||||
@@ -2655,7 +2700,7 @@ skip:
|
||||
if (!have_block)
|
||||
expect_unknown = true;
|
||||
}
|
||||
if (!first)
|
||||
if (0 < i)
|
||||
{
|
||||
// after the first, blocks may be known or unknown, but if they are known,
|
||||
// they should be at the same height if on the main chain
|
||||
@@ -2696,10 +2741,10 @@ skip:
|
||||
expect_unknown = true;
|
||||
}
|
||||
const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
|
||||
context.m_expected_heights.push_back(arg.m_block_ids[i]);
|
||||
context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
|
||||
if (++added == n_use_blocks)
|
||||
break;
|
||||
first = false;
|
||||
}
|
||||
context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
|
||||
|
||||
@@ -2908,6 +2953,16 @@ skip:
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::drop_connection(const boost::uuids::uuid& id)
|
||||
{
|
||||
m_p2p->for_connection(id, [this](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
// This _could be_ outside of strand, so careful on actions
|
||||
drop_connection(context, true, false);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
void t_cryptonote_protocol_handler<t_core>::drop_connections(const epee::net_utils::network_address address)
|
||||
{
|
||||
MWARNING("dropping connections to " << address.str());
|
||||
@@ -2924,6 +2979,7 @@ skip:
|
||||
{
|
||||
m_block_queue.flush_spans(id, true);
|
||||
m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
|
||||
// This _could be_ outside of strand, so careful on actions
|
||||
drop_connection(context, true, false);
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace cryptonote
|
||||
BURN = 5,
|
||||
STAKE = 6,
|
||||
RETURN = 7,
|
||||
MAX = 7
|
||||
AUDIT = 8,
|
||||
MAX = 8
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
|
||||
#include "levin_notify.h"
|
||||
|
||||
#include <boost/asio/dispatch.hpp>
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
@@ -221,7 +223,7 @@ namespace levin
|
||||
`dispatch` is used heavily, which means "execute immediately in _this_
|
||||
thread if the strand is not in use, otherwise queue the callback to be
|
||||
executed immediately after the strand completes its current task".
|
||||
`post` is used where deferred execution to an `asio::io_service::run`
|
||||
`post` is used where deferred execution to an `asio::io_context::run`
|
||||
thread is preferred.
|
||||
|
||||
The strand per "zone" is useful because the levin
|
||||
@@ -238,7 +240,7 @@ namespace levin
|
||||
//! A queue of levin messages for a noise i2p/tor link
|
||||
struct noise_channel
|
||||
{
|
||||
explicit noise_channel(boost::asio::io_service& io_service)
|
||||
explicit noise_channel(boost::asio::io_context& io_service)
|
||||
: active(nullptr),
|
||||
queue(),
|
||||
strand(io_service),
|
||||
@@ -246,7 +248,7 @@ namespace levin
|
||||
connection(boost::uuids::nil_uuid())
|
||||
{}
|
||||
|
||||
// `asio::io_service::strand` cannot be copied or moved
|
||||
// `asio::io_context::strand` cannot be copied or moved
|
||||
noise_channel(const noise_channel&) = delete;
|
||||
noise_channel& operator=(const noise_channel&) = delete;
|
||||
|
||||
@@ -254,7 +256,7 @@ namespace levin
|
||||
|
||||
epee::byte_slice active;
|
||||
std::deque<epee::byte_slice> queue;
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::io_context::strand strand;
|
||||
boost::asio::steady_timer next_noise;
|
||||
boost::uuids::uuid connection;
|
||||
};
|
||||
@@ -264,7 +266,7 @@ namespace levin
|
||||
{
|
||||
struct zone
|
||||
{
|
||||
explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs)
|
||||
explicit zone(boost::asio::io_context& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs)
|
||||
: p2p(std::move(p2p)),
|
||||
noise(std::move(noise_in)),
|
||||
next_epoch(io_service),
|
||||
@@ -286,7 +288,7 @@ namespace levin
|
||||
const epee::byte_slice noise; //!< `!empty()` means zone is using noise channels
|
||||
boost::asio::steady_timer next_epoch;
|
||||
boost::asio::steady_timer flush_txs;
|
||||
boost::asio::io_service::strand strand;
|
||||
boost::asio::io_context::strand strand;
|
||||
struct context_t {
|
||||
std::vector<cryptonote::blobdata> fluff_txs;
|
||||
std::chrono::steady_clock::time_point flush_time;
|
||||
@@ -396,6 +398,8 @@ namespace levin
|
||||
for (auto& connection : connections)
|
||||
{
|
||||
std::sort(connection.first.begin(), connection.first.end()); // don't leak receive order
|
||||
connection.first.erase(std::unique(connection.first.begin(), connection.first.end()),
|
||||
connection.first.end());
|
||||
make_payload_send_txs(*zone_->p2p, std::move(connection.first), connection.second, zone_->pad_txs, true);
|
||||
}
|
||||
|
||||
@@ -452,7 +456,7 @@ namespace levin
|
||||
|
||||
if (next_flush == std::chrono::steady_clock::time_point::max())
|
||||
MWARNING("Unable to send transaction(s), no available connections");
|
||||
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expires_at())
|
||||
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expiry())
|
||||
fluff_flush::queue(std::move(zone), next_flush);
|
||||
}
|
||||
};
|
||||
@@ -513,7 +517,7 @@ namespace levin
|
||||
for (auto id = zone->map.begin(); id != zone->map.end(); ++id)
|
||||
{
|
||||
const std::size_t i = id - zone->map.begin();
|
||||
zone->channels[i].strand.post(update_channel{zone, i, *id});
|
||||
boost::asio::post(zone->channels[i].strand, update_channel{zone, i, *id});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,7 +676,7 @@ namespace levin
|
||||
MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
|
||||
" - no suitable outbound connections at height " << height);
|
||||
|
||||
zone_->strand.post(update_channels{zone_, std::move(connections)});
|
||||
boost::asio::post(zone_->strand, update_channels{zone_, std::move(connections)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,7 +706,8 @@ namespace levin
|
||||
const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY;
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
auto connections = get_out_connections(*(zone_->p2p), core_);
|
||||
zone_->strand.dispatch(
|
||||
boost::asio::dispatch(
|
||||
zone_->strand,
|
||||
change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing}
|
||||
);
|
||||
|
||||
@@ -713,7 +718,7 @@ namespace levin
|
||||
};
|
||||
} // anonymous
|
||||
|
||||
notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core)
|
||||
notify::notify(boost::asio::io_context& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core)
|
||||
: zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), zone, pad_txs))
|
||||
, core_(std::addressof(core))
|
||||
{
|
||||
@@ -741,9 +746,14 @@ namespace levin
|
||||
notify::status notify::get_status() const noexcept
|
||||
{
|
||||
if (!zone_)
|
||||
return {false, false};
|
||||
return {false, false, false};
|
||||
|
||||
return {!zone_->noise.empty(), CRYPTONOTE_NOISE_CHANNELS <= zone_->connection_count};
|
||||
// `connection_count` is only set when `!noise.empty()`.
|
||||
const std::size_t connection_count = zone_->connection_count;
|
||||
bool has_outgoing = connection_count;
|
||||
if (zone_->noise.empty())
|
||||
has_outgoing = zone_->p2p->get_out_connections_count();
|
||||
return {!zone_->noise.empty(), CRYPTONOTE_NOISE_CHANNELS <= connection_count, has_outgoing};
|
||||
}
|
||||
|
||||
void notify::new_out_connection()
|
||||
@@ -751,7 +761,8 @@ namespace levin
|
||||
if (!zone_ || zone_->noise.empty() || CRYPTONOTE_NOISE_CHANNELS <= zone_->connection_count)
|
||||
return;
|
||||
|
||||
zone_->strand.dispatch(
|
||||
boost::asio::dispatch(
|
||||
zone_->strand,
|
||||
update_channels{zone_, get_out_connections(*(zone_->p2p), core_)}
|
||||
);
|
||||
}
|
||||
@@ -762,7 +773,7 @@ namespace levin
|
||||
return;
|
||||
|
||||
auto& zone = zone_;
|
||||
zone_->strand.dispatch([zone, id, is_income]{
|
||||
boost::asio::dispatch(zone_->strand, [zone, id, is_income] {
|
||||
zone->contexts[id] = {
|
||||
.fluff_txs = {},
|
||||
.flush_time = std::chrono::steady_clock::time_point::max(),
|
||||
@@ -777,7 +788,7 @@ namespace levin
|
||||
return;
|
||||
|
||||
auto& zone = zone_;
|
||||
zone_->strand.dispatch([zone, id]{
|
||||
boost::asio::dispatch(zone_->strand, [zone, id]{
|
||||
zone->contexts.erase(id);
|
||||
});
|
||||
}
|
||||
@@ -852,7 +863,8 @@ namespace levin
|
||||
|
||||
for (std::size_t channel = 0; channel < zone_->channels.size(); ++channel)
|
||||
{
|
||||
zone_->channels[channel].strand.dispatch(
|
||||
boost::asio::dispatch(
|
||||
zone_->channels[channel].strand,
|
||||
queue_covert_notify{zone_, message.clone(), channel}
|
||||
);
|
||||
}
|
||||
@@ -871,7 +883,8 @@ namespace levin
|
||||
if (zone_->nzone == epee::net_utils::zone::public_)
|
||||
{
|
||||
// this will change a local/forward tx to stem or fluff ...
|
||||
zone_->strand.dispatch(
|
||||
boost::asio::dispatch(
|
||||
zone_->strand,
|
||||
dandelionpp_notify{zone_, core_, std::move(txs), source, tx_relay}
|
||||
);
|
||||
break;
|
||||
@@ -884,7 +897,7 @@ namespace levin
|
||||
ipv4/6. Marking it as "fluff" here will make the tx immediately
|
||||
visible externally from this node, which is not desired. */
|
||||
core_->on_transactions_relayed(epee::to_span(txs), tx_relay);
|
||||
zone_->strand.dispatch(fluff_notify{zone_, std::move(txs), source});
|
||||
boost::asio::dispatch(zone_->strand, fluff_notify{zone_, std::move(txs), source});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -75,7 +75,8 @@ namespace levin
|
||||
struct status
|
||||
{
|
||||
bool has_noise;
|
||||
bool connections_filled;
|
||||
bool connections_filled; //!< True when has zone has `CRYPTONOTE_NOISE_CHANNELS` outgoing noise channels
|
||||
bool has_outgoing; //!< True when zone has outgoing connections
|
||||
};
|
||||
|
||||
//! Construct an instance that cannot notify.
|
||||
@@ -85,7 +86,7 @@ namespace levin
|
||||
{}
|
||||
|
||||
//! Construct an instance with available notification `zones`.
|
||||
explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core);
|
||||
explicit notify(boost::asio::io_context& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core);
|
||||
|
||||
notify(const notify&) = delete;
|
||||
notify(notify&&) = default;
|
||||
|
||||
@@ -696,6 +696,16 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args)
|
||||
std::ifstream ifs(ban_list_path.string());
|
||||
for (std::string line; std::getline(ifs, line); )
|
||||
{
|
||||
// ignore comments after '#' character
|
||||
const size_t pound_idx = line.find('#');
|
||||
if (pound_idx != std::string::npos)
|
||||
line.resize(pound_idx);
|
||||
|
||||
// trim whitespace and ignore empty lines
|
||||
boost::trim(line);
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
auto subnet = net::get_ipv4_subnet_address(line);
|
||||
if (subnet)
|
||||
{
|
||||
|
||||
+6
-7
@@ -83,7 +83,7 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm)
|
||||
}
|
||||
|
||||
uint16_t rpc_port;
|
||||
if (!string_tools::get_xtype_from_string(rpc_port, rpc_port_str))
|
||||
if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str))
|
||||
{
|
||||
throw std::runtime_error("invalid RPC port " + rpc_port_str);
|
||||
}
|
||||
@@ -141,9 +141,9 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
|
||||
miner_key_file << "Miner account address:" << std::endl;
|
||||
miner_key_file << cryptonote::get_account_address_as_str((network_type)nettype, false, miner_acc1.get_keys().m_account_address);
|
||||
miner_key_file << std::endl<< "Miner spend secret key:" << std::endl;
|
||||
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(miner_acc1.get_keys().m_spend_secret_key));
|
||||
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_spend_secret_key))));
|
||||
miner_key_file << std::endl << "Miner view secret key:" << std::endl;
|
||||
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(miner_acc1.get_keys().m_view_secret_key));
|
||||
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_view_secret_key))));
|
||||
miner_key_file << std::endl << std::endl;
|
||||
miner_key_file.close();
|
||||
|
||||
@@ -153,13 +153,13 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
|
||||
std::cout << "Object:" << std::endl;
|
||||
std::cout << obj_to_json_str(tx_genesis) << std::endl << std::endl;
|
||||
|
||||
std::cout << "Gennerating miner wallet..." << std::endl;
|
||||
std::cout << "Generating miner wallet..." << std::endl;
|
||||
std::cout << "Miner account address:" << std::endl;
|
||||
std::cout << cryptonote::get_account_address_as_str((network_type)nettype, false, miner_acc1.get_keys().m_account_address);
|
||||
std::cout << std::endl << "Miner spend secret key:" << std::endl;
|
||||
epee::to_hex::formatted(std::cout, epee::as_byte_span(miner_acc1.get_keys().m_spend_secret_key));
|
||||
epee::to_hex::formatted(std::cout, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_spend_secret_key))));
|
||||
std::cout << std::endl << "Miner view secret key:" << std::endl;
|
||||
epee::to_hex::formatted(std::cout, epee::as_byte_span(miner_acc1.get_keys().m_view_secret_key));
|
||||
epee::to_hex::formatted(std::cout, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_view_secret_key))));
|
||||
std::cout << std::endl << std::endl;
|
||||
|
||||
std::stringstream ss;
|
||||
@@ -168,7 +168,6 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
|
||||
std::string tx_hex = ss.str();
|
||||
std::cout << "Insert this line into your coin configuration file: " << std::endl;
|
||||
std::cout << "std::string const GENESIS_TX = \"" << epee::string_tools::buff_to_hex_nodelimer(tx_hex) << "\";" << std::endl;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1064,7 +1064,7 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash,
|
||||
cryptonote::blobdata blob;
|
||||
std::string source = as_hex.empty() ? pruned_as_hex + prunable_as_hex : as_hex;
|
||||
bool pruned = !pruned_as_hex.empty() && prunable_as_hex.empty();
|
||||
if (!string_tools::parse_hexstr_to_binbuff(source, blob))
|
||||
if (!epee::string_tools::parse_hexstr_to_binbuff(source, blob))
|
||||
{
|
||||
tools::fail_msg_writer() << "Failed to parse tx to get json format";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2017-2023, The Monero Project
|
||||
// Copyright (c) 2017-2024, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
@@ -317,13 +317,15 @@ namespace hw {
|
||||
{
|
||||
// sending change to yourself; derivation = a*R
|
||||
r = generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")");
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", <viewkey>)");
|
||||
}
|
||||
else
|
||||
{
|
||||
// sending to the recipient; derivation = r*A (or s*C in the subaddress scheme)
|
||||
r = generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << (dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key) << ")");
|
||||
const crypto::secret_key &tx_privkey{dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key};
|
||||
r = generate_key_derivation(dst_entr.addr.m_view_public_key, tx_privkey, derivation);
|
||||
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation("
|
||||
<< dst_entr.addr.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{tx_privkey} << ")");
|
||||
}
|
||||
|
||||
if (need_additional_txkeys)
|
||||
|
||||
@@ -528,6 +528,7 @@ namespace hw {
|
||||
{0x2c97, 0x0004, 0, 0xffa0},
|
||||
{0x2c97, 0x0005, 0, 0xffa0},
|
||||
{0x2c97, 0x0006, 0, 0xffa0},
|
||||
{0x2c97, 0x0007, 0, 0xffa0},
|
||||
};
|
||||
|
||||
bool device_ledger::connect(void) {
|
||||
@@ -1929,7 +1930,7 @@ namespace hw {
|
||||
|
||||
// ====== Aout, Bout, AKout, C, v, k ======
|
||||
kv_offset = data_offset;
|
||||
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus) {
|
||||
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs) {
|
||||
C_offset = kv_offset+ (8)*outputs_size;
|
||||
} else {
|
||||
C_offset = kv_offset+ (32+32)*outputs_size;
|
||||
@@ -1946,7 +1947,7 @@ namespace hw {
|
||||
offset = set_command_header(INS_VALIDATE, 0x02, i+1);
|
||||
//options
|
||||
this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
|
||||
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus)?0x02:0x00;
|
||||
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs)?0x02:0x00;
|
||||
offset += 1;
|
||||
//is_subaddress
|
||||
this->buffer_send[offset] = outKeys.is_subaddress;
|
||||
@@ -1967,7 +1968,7 @@ namespace hw {
|
||||
memmove(this->buffer_send+offset, data+C_offset,32);
|
||||
offset += 32;
|
||||
C_offset += 32;
|
||||
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus) {
|
||||
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs) {
|
||||
//k
|
||||
memset(this->buffer_send+offset, 0, 32);
|
||||
offset += 32;
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/format.hpp>
|
||||
@@ -614,8 +613,7 @@ namespace trezor{
|
||||
}
|
||||
|
||||
udp::resolver resolver(m_io_service);
|
||||
udp::resolver::query query(udp::v4(), m_device_host, std::to_string(m_device_port));
|
||||
m_endpoint = *resolver.resolve(query);
|
||||
m_endpoint = *resolver.resolve(udp::v4(), m_device_host, std::to_string(m_device_port)).begin();
|
||||
|
||||
m_socket.reset(new udp::socket(m_io_service));
|
||||
m_socket->open(udp::v4());
|
||||
|
||||
@@ -244,7 +244,7 @@ namespace trezor {
|
||||
int m_device_port;
|
||||
|
||||
std::unique_ptr<udp::socket> m_socket;
|
||||
boost::asio::io_service m_io_service;
|
||||
boost::asio::io_context m_io_service;
|
||||
boost::asio::deadline_timer m_deadline;
|
||||
udp::endpoint m_endpoint;
|
||||
};
|
||||
|
||||
@@ -35,8 +35,29 @@ const hardfork_t mainnet_hard_forks[] = {
|
||||
// version 1 from the start of the blockchain
|
||||
{ 1, 1, 0, 1341378000 },
|
||||
|
||||
// version 2 starts from block 1000, which is on or around the 20th of March, 2016. Fork time finalised on 2015-09-20. No fork voting occurs for the v2 fork.
|
||||
//{ 2, 1000, 0, 1442763710 },
|
||||
// version 2 starts from block 89800, which is on or around the 4th of November, 2024. Fork time finalised on 2024-10-21. No fork voting occurs for the v2 fork.
|
||||
{ 2, 89800, 0, 1729518000 },
|
||||
|
||||
// version 3 starts from block 121100, which is on or around the 19th of December, 2024. Fork time finalised on 2024-12-18. No fork voting occurs for the v3 fork.
|
||||
{ 3, 121100, 0, 1734516900 },
|
||||
|
||||
// version 4 starts from block 121100, which is on or around the 20th of December, 2024. Fork time finalised on 2024-12-19. No fork voting occurs for the v4 fork.
|
||||
{ 4, 121800, 0, 1734607000 },
|
||||
|
||||
// version 5 starts from block 136100, which is on or around the 9th of January, 2025. Fork time finalised on 2025-01-08. No fork voting occurs for the v5 fork.
|
||||
{ 5, 136100, 0, 1736265945 },
|
||||
|
||||
// version 6 starts from block 154750, which is on or around the 4th of February, 2025. Fork time finalised on 2025-01-31. No fork voting occurs for the v6 fork.
|
||||
{ 6, 154750, 0, 1738336000 },
|
||||
|
||||
// version 7 starts from block 161900, which is on or around the 14th of February, 2025. Fork time finalised on 2025-02-04. No fork voting occurs for the v7 fork.
|
||||
{ 7, 161900, 0, 1739264400 },
|
||||
|
||||
// version 8 starts from block 172000, which is on or around the 28th of February, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v8 fork.
|
||||
{ 8, 172000, 0, 1740390000 },
|
||||
|
||||
// version 9 starts from block 179200, which is on or around the 10th of March, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v9 fork.
|
||||
{ 9, 179200, 0, 1740393800 },
|
||||
};
|
||||
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
|
||||
const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
@@ -45,8 +66,29 @@ const hardfork_t testnet_hard_forks[] = {
|
||||
// version 1 from the start of the blockchain
|
||||
{ 1, 1, 0, 1341378000 },
|
||||
|
||||
// version 2 starts from block 1000, which is on or around the 23rd of November, 2015. Fork time finalised on 2015-11-20. No fork voting occurs for the v2 fork.
|
||||
//{ 2, 1000, 0, 1445355000 },
|
||||
// version 2 starts from block 250
|
||||
{ 2, 250, 0, 1445355000 },
|
||||
|
||||
// version 3 starts from block 500
|
||||
{ 3, 500, 0, 1729518000 },
|
||||
|
||||
// version 4 (full proofs) starts from block 600
|
||||
{ 4, 600, 0, 1734607000 },
|
||||
|
||||
// version 5 (TX shutdown) starts from block 800
|
||||
{ 5, 800, 0, 1734607005 },
|
||||
|
||||
// version 6 (audit 1) starts from block 815
|
||||
{ 6, 815, 0, 1734608000 },
|
||||
|
||||
// version 7 (audit 1 pause, blacklist controlling payouts) starts from block 900
|
||||
{ 7, 900, 0, 1739264400 },
|
||||
|
||||
// version 8 (audit 1 resume) starts from block 950
|
||||
{ 8, 950, 0, 1739270000 },
|
||||
|
||||
// version 9 (audit 1 complete, whitelist controlling payouts) starts from block 1000
|
||||
{ 9, 1000, 0, 1739280000 },
|
||||
};
|
||||
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
|
||||
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
|
||||
|
||||
@@ -133,6 +133,7 @@ namespace lmdb
|
||||
//! \pre `!is_end()` \return Current key
|
||||
K get_key() const noexcept
|
||||
{
|
||||
static_assert(std::is_trivially_copyable<K>(), "key is not memcpy safe");
|
||||
assert(!is_end());
|
||||
K out;
|
||||
std::memcpy(std::addressof(out), key.data(), sizeof(out));
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ namespace lmdb
|
||||
static expect<F> get_value(MDB_val value) noexcept
|
||||
{
|
||||
static_assert(std::is_same<U, V>(), "bad MONERO_FIELD?");
|
||||
static_assert(std::is_pod<F>(), "F must be POD");
|
||||
static_assert(std::is_trivially_copyable<F>(), "F must be memcpy safe");
|
||||
static_assert(sizeof(F) + offset <= sizeof(U), "bad field type and/or offset");
|
||||
|
||||
if (value.mv_size != sizeof(U))
|
||||
|
||||
+3
-2
@@ -111,6 +111,7 @@ namespace lmdb
|
||||
template<typename T, std::size_t offset = 0>
|
||||
inline int less(MDB_val const* left, MDB_val const* right) noexcept
|
||||
{
|
||||
static_assert(std::is_trivially_copyable<T>(), "memcpy will not work");
|
||||
if (!left || !right || left->mv_size < sizeof(T) + offset || right->mv_size < sizeof(T) + offset)
|
||||
{
|
||||
assert("invalid use of custom comparison" == 0);
|
||||
@@ -127,7 +128,7 @@ namespace lmdb
|
||||
/*!
|
||||
A LMDB comparison function that uses `std::memcmp`.
|
||||
|
||||
\toaram T is `!epee::has_padding`
|
||||
\toaram T has standard layout and an alignment of 1
|
||||
\tparam offset to `T` within the value.
|
||||
|
||||
\return The result of `std::memcmp` over the value.
|
||||
@@ -135,7 +136,7 @@ namespace lmdb
|
||||
template<typename T, std::size_t offset = 0>
|
||||
inline int compare(MDB_val const* left, MDB_val const* right) noexcept
|
||||
{
|
||||
static_assert(!epee::has_padding<T>(), "memcmp will not work");
|
||||
static_assert(std::is_standard_layout<T>() && alignof(T) == 1, "memcmp will not work");
|
||||
if (!left || !right || left->mv_size < sizeof(T) + offset || right->mv_size < sizeof(T) + offset)
|
||||
{
|
||||
assert("invalid use of custom comparison" == 0);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user