Compare commits

...

65 Commits

Author SHA1 Message Date
luigi1111 e06129bb4d Merge pull request #8805
4f1262b build: prepare v0.18.2.2 (selsta)
2023-04-02 20:53:20 -04:00
luigi1111 a371e60a30 Merge pull request #8813
059b975 cryptonote core/protocol: don't drop peers for soft offenses (jeffro256)
2023-04-02 20:46:21 -04:00
luigi1111 2f62dd5b78 Merge pull request #8811
c742fa4 Fixed deadlock and crash when syncing with full dataset on Windows (SChernykh)
2023-04-02 20:45:47 -04:00
jeffro256 059b975388 cryptonote core/protocol: don't drop peers for soft offenses
Also: txs with tx_extra which is too large will not get published to ZMQ

Co-authored-by: SChernykh <sergey.v.chernykh@gmail.com>
2023-03-29 02:07:15 -05:00
SChernykh c742fa4c6e Fixed deadlock and crash when syncing with full dataset on Windows
It's not allowed to use WaitForSingleObject with _beginthread, because the thread closes its own handle before exiting.

So the wait function will either wait on an invalid handle, or on a different handle used by something else.

Or, if it starts waiting before the thread exits, the behavior is undefined according to MS: "If this handle is closed while the wait is still pending, the function's behavior is undefined."

In my test sync I observed threads getting stuck infinitely on WaitForSingleObject, and then rx_set_main_seedhash spamming new threads when RandomX seed changes again. Eventually the system ran out of resources, and monerod aborted with "Couldn't start RandomX seed thread" message.

This PR fixes it by using `_beginthreadex` instead and explicitly closing the handle when it's safe.
2023-03-29 08:44:20 +02:00
selsta 4f1262bae9 build: prepare v0.18.2.2 2023-03-27 18:52:04 +02:00
luigi1111 4f47fd2626 Merge pull request #8801
1328048 wallet2: fix infinite loop in fake out selection (Crypto City)
2023-03-27 09:17:55 -04:00
Crypto City 132804811d wallet2: fix infinite loop in fake out selection
The gamma picker and the caller code did not quite agree on the
number of rct outputs available for use - by one block - which
caused an infinite loop if the picker could never pick outputs
from that block but already had picked all other outputs from
previous blocks.

Also change the range to select from using code from UkoeHB.
2023-03-25 19:26:43 +00:00
luigi1111 25645e5d23 Merge pull request #8785
cdeb286 build: prepare v0.18.2.1 (selsta)
2023-03-24 22:55:49 -04:00
luigi1111 0e2c2ddd9c Merge pull request #8787
c4cfaa4 p2p: do not log to global when re-blocking a subnet (moneromooo-monero)
f0e326b p2p: avoid spam blocking ipv4 addresses in a blocked subnet (moneromooo-monero)
2023-03-24 22:55:29 -04:00
moneromooo-monero c4cfaa4567 p2p: do not log to global when re-blocking a subnet 2023-03-19 02:58:38 +01:00
moneromooo-monero f0e326be58 p2p: avoid spam blocking ipv4 addresses in a blocked subnet 2023-03-19 02:58:38 +01:00
luigi1111 225e5ba571 Merge pull request #8784
5900ed3 Add a size limit for tx_extra in tx pool (tevador)
2023-03-18 18:23:14 -04:00
luigi1111 66f57299a2 Merge pull request #8781
c59e009 verRctNonSemanticsSimpleCached: fix fragility (Jeffrey Ryan)
2023-03-18 18:22:01 -04:00
luigi1111 d7821a02c4 Merge pull request #8779
14de562 device: Add ledger Stax device id to device detection (Francois Beutin)
2023-03-18 18:21:25 -04:00
luigi1111 b4519c6bbd Merge pull request #8746
77d883e workflows: update dependencies to fix warnings (selsta)
2023-03-18 18:20:17 -04:00
selsta cdeb286359 build: prepare v0.18.2.1 2023-03-18 21:23:42 +01:00
tevador 5900ed3706 Add a size limit for tx_extra in tx pool 2023-03-18 20:01:58 +01:00
Jeffrey Ryan c59e0096b6 verRctNonSemanticsSimpleCached: fix fragility 2023-03-17 18:46:34 -05:00
Francois Beutin 14de562a6f device: Add ledger Stax device id to device detection 2023-03-17 21:27:51 +01:00
selsta 77d883e507 workflows: update dependencies to fix warnings 2023-02-20 04:11:35 +01:00
luigi1111 99be9a044f Merge pull request #8739
dc18efa build: prepare v0.18.2.0 (selsta)
2023-02-15 10:47:13 -05:00
luigi1111 75bec6336a Merge pull request #8738
d8e39bd depends: bump openssl to 1.1.1t (tobtoht)
2023-02-15 10:46:47 -05:00
luigi1111 68a73a2b4d Merge pull request #8721
988056d p2p: add plowsof seed nodes (selsta)
ce4ef6d p2p: remove offline seed nodes (selsta)
2023-02-15 10:44:56 -05:00
selsta dc18efa3d7 build: prepare v0.18.2.0 2023-02-08 22:18:30 +01:00
tobtoht d8e39bd381 depends: bump openssl to 1.1.1t
https://www.openssl.org/news/secadv/20230207.txt

Patch can be removed, it was included upstream.
2023-02-07 20:56:20 +01:00
luigi1111 0f15707077 Merge pull request #8723
573a369 blockchain-stats: print any remaining data at end of loop (Howard Chu)
2023-02-06 12:38:11 -05:00
luigi1111 f38b07335a Merge pull request #8714
15384cc depends: bump hidapi/libusb (tobtoht)
2023-02-06 12:37:48 -05:00
luigi1111 057a77a09f Merge pull request #8706
f456b3f Demote large pages warning to mdebug (SChernykh)
480b050 RandomX: print VM allocation warnings only once (SChernykh)
2023-02-06 12:36:10 -05:00
Howard Chu 573a369a8a blockchain-stats: print any remaining data at end of loop
Fix #8711
2023-01-29 11:09:02 +00:00
selsta 988056dc09 p2p: add plowsof seed nodes 2023-01-27 14:17:54 +01:00
selsta ce4ef6da96 p2p: remove offline seed nodes 2023-01-27 14:17:54 +01:00
tobtoht 15384cc135 depends: bump hidapi/libusb
fixes Trezor connectivity issues on Windows 10/11

Co-authored-by: selsta <selsta@sent.at>
2023-01-25 21:52:42 +01:00
SChernykh f456b3f023 Demote large pages warning to mdebug 2023-01-17 18:16:47 +01:00
SChernykh 480b050cc3 RandomX: print VM allocation warnings only once 2023-01-11 19:18:41 +01:00
luigi1111 c48f572e46 Merge pull request #8676
29208a3 Cache successful erRctNonSemanticsSimple calls (SChernykh)
2023-01-11 12:28:08 -05:00
luigi1111 f73a2b1587 Merge pull request #8683
cbc297a common: add missing includes (selsta)
2023-01-11 12:13:23 -05:00
luigi1111 1d20b8171d Merge pull request #8678
f698f2b Refactored rx-slow-hash.c (SChernykh)
2023-01-11 12:12:28 -05:00
luigi1111 b0ea7cb528 Merge pull request #8654
5973985 workflows: set a public DNS when doing tests (selsta)
2023-01-11 11:43:59 -05:00
luigi1111 153819fc4c Merge pull request #8649
2c24322 DNSResolver: fix not handling hostnames without dot characters [release] (Jeffrey Ryan)
2023-01-11 11:41:56 -05:00
luigi1111 cbc5cf43f2 Merge pull request #8644
38d4811 p2p: fix exclusive node DNS resolution for certain hosts [release] (Jeffrey Ryan)
2023-01-11 11:40:13 -05:00
luigi1111 1976c9afa0 Merge pull request #8641
146cac0 p2p: fix back ping to discover healthy peers to connect to (j-berman)
2023-01-11 11:39:15 -05:00
SChernykh 29208a33cb Cache successful verRctNonSemanticsSimple calls 2022-12-20 22:19:00 +01:00
selsta cbc297acfb common: add missing includes 2022-12-18 19:47:01 +01:00
SChernykh f698f2b708 Refactored rx-slow-hash.c
- Straight-forward call interface: `void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash)`
- Consensus chain seed hash is now updated by calling `rx_set_main_seedhash` whenever a block is added/removed or a reorg happens
- `rx_slow_hash` will compute correct hash no matter if `rx_set_main_seedhash` was called or not (the only difference is performance)
- New environment variable `MONERO_RANDOMX_FULL_MEM` to force use the full dataset for PoW verification (faster block verification)
- When dataset is used for PoW verification, dataset updates don't stall other threads (verification is done in light mode then)
- When mining is running, PoW checks now also use dataset for faster verification
2022-12-14 07:21:00 +01:00
luigi1111 8cb10345d6 Merge pull request #8642
8c53995 Fix static builds for Ubuntu 22.04 (AgoraDesk / LocalMonero)
2022-12-01 01:13:30 -06:00
luigi1111 47b41eabfe Merge pull request #8636
02b24cb workflows: ubuntu 18.04 is deprecated (selsta)
2022-12-01 01:12:53 -06:00
luigi1111 abd37fcf5b Merge pull request #8628
1bb5d25 Fix dandelion++ fluff/stem bug with local txes (Lee Clagett)
2022-12-01 01:11:14 -06:00
luigi1111 cce309512c Merge pull request #8615
85c9fe5 wallet2: fix create view-only wallet from existing wallet (j-berman)
2022-12-01 01:06:16 -06:00
luigi1111 f5d701c550 Merge pull request #8611
401dda5 wallet_api: take priority into account when estimating fee (selsta)
2022-12-01 01:05:40 -06:00
luigi1111 d05298358c Merge pull request #8604
cbf636c workflows: build gitian on tag (selsta)
2022-12-01 01:04:09 -06:00
selsta 5973985148 workflows: set a public DNS when doing tests 2022-11-29 00:09:44 +01:00
Jeffrey Ryan 2c2432245f DNSResolver: fix not handling hostnames without dot characters [release]
Unrelated, but similar code-wise to #8643. There is a check in `DNSResolver` which automatically fails to resolve hostnames which do not contain the `.` character. This PR removes that check.
2022-11-21 21:16:16 -06:00
Jeffrey Ryan 38d4811c89 p2p: fix exclusive node DNS resolution for certain hosts [release]
Fixes #8633. The function `append_net_address` did not parse hostname + port addresses (e.g. `bar:29080`) correctly if the hostname did not contain a `'.'` character.

@vtnerd comments 1

clear up 2nd conditional statement
2022-11-17 18:57:04 -06:00
selsta cbf636c7a9 workflows: build gitian on tag 2022-11-17 02:48:22 +01:00
AgoraDesk / LocalMonero 8c53995a88 Fix static builds for Ubuntu 22.04
Link libbsd, libmd, libprotokit for ZMQ to fix static builds for Ubuntu 22.04
2022-11-16 12:08:04 -05:00
j-berman 146cac02ca p2p: fix back ping to discover healthy peers to connect to 2022-11-15 18:02:25 -08:00
selsta 02b24cb353 workflows: ubuntu 18.04 is deprecated 2022-11-14 02:16:31 +01:00
luigi1111 e6f9c0013b Merge pull request #8594
d7445b5 workflows: ubuntu 18.04 is deprecated (selsta)
2022-10-28 00:53:08 -04:00
luigi1111 5d4ace8cae Merge pull request #8578
07f8e9e epee: dont shrink slice when storing to binary [release] (Jeffrey Ryan)
2022-10-28 00:51:18 -04:00
Lee Clagett 1bb5d25e31 Fix dandelion++ fluff/stem bug with local txes 2022-10-25 16:01:09 -04:00
j-berman 85c9fe515d wallet2: fix create view-only wallet from existing wallet 2022-10-18 13:47:50 -05:00
selsta 401dda5f10 wallet_api: take priority into account when estimating fee 2022-10-13 03:36:51 +02:00
selsta d7445b576f workflows: ubuntu 18.04 is deprecated
And will soon be removed.
2022-09-24 21:04:28 +02:00
Jeffrey Ryan 07f8e9e891 epee: dont shrink slice when storing to binary [release] 2022-09-20 12:04:14 -05:00
57 changed files with 1623 additions and 591 deletions
+18 -16
View File
@@ -27,10 +27,10 @@ jobs:
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/cache@v2
- uses: actions/cache@v3
with:
path: /Users/runner/Library/Caches/ccache
key: ccache-${{ runner.os }}-build-${{ github.sha }}
@@ -51,15 +51,15 @@ jobs:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/cache@v2
- uses: actions/cache@v3
with:
path: C:\Users\runneradmin\.ccache
key: ccache-${{ runner.os }}-build-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-build-
- uses: eine/setup-msys2@v2
- uses: msys2/setup-msys2@v2
with:
update: true
install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-unbound git
@@ -77,12 +77,12 @@ jobs:
CCACHE_TEMPDIR: /tmp/.ccache-temp
strategy:
matrix:
os: [ubuntu-latest, ubuntu-18.04]
os: [ubuntu-22.04, ubuntu-20.04]
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/cache@v2
- uses: actions/cache@v3
with:
path: ~/.ccache
key: ccache-${{ runner.os }}-build-${{ matrix.os }}-${{ github.sha }}
@@ -101,14 +101,14 @@ jobs:
${{env.BUILD_DEFAULT_LINUX}}
libwallet-ubuntu:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/cache@v2
- uses: actions/cache@v3
with:
path: ~/.ccache
key: ccache-${{ runner.os }}-libwallet-${{ github.sha }}
@@ -129,15 +129,15 @@ jobs:
test-ubuntu:
needs: build-ubuntu
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
submodules: recursive
- name: ccache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/.ccache
key: ccache-${{ runner.os }}-build-ubuntu-latest-${{ github.sha }}
@@ -155,6 +155,7 @@ jobs:
- name: tests
env:
CTEST_OUTPUT_ON_FAILURE: ON
DNS_PUBLIC: tcp://9.9.9.9
run: |
${{env.CCACHE_SETTINGS}}
${{env.BUILD_DEFAULT_LINUX}}
@@ -166,8 +167,9 @@ jobs:
source-archive:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: archive
run: |
@@ -176,7 +178,7 @@ jobs:
export OUTPUT="$VERSION.tar"
echo "OUTPUT=$OUTPUT" >> $GITHUB_ENV
/home/runner/.local/bin/git-archive-all --prefix "$VERSION/" --force-submodules "$OUTPUT"
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
with:
name: ${{ env.OUTPUT }}
path: /home/runner/work/monero/monero/${{ env.OUTPUT }}
+7 -6
View File
@@ -18,7 +18,7 @@ env:
jobs:
build-cross:
runs-on: ubuntu-18.04
runs-on: ubuntu-20.04
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
strategy:
@@ -57,19 +57,20 @@ jobs:
packages: "clang-8 gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
name: ${{ matrix.toolchain.name }}
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
# Most volatile cache
- name: ccache
uses: actions/cache@v2
uses: actions/cache@v3
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@v2
uses: actions/cache@v3
with:
path: contrib/depends/built
key: depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
@@ -78,7 +79,7 @@ jobs:
depends-${{ matrix.toolchain.host }}-
# Static cache
- name: OSX SDK cache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: contrib/depends/sdk-sources
key: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
@@ -96,7 +97,7 @@ jobs:
run: |
${{env.CCACHE_SETTINGS}}
make depends target=${{ matrix.toolchain.host }} -j2
- uses: actions/upload-artifact@v2
- uses: actions/upload-artifact@v3
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin11' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
with:
name: ${{ matrix.toolchain.name }}
+49
View File
@@ -0,0 +1,49 @@
name: ci/gh-actions/gitian
on:
push:
tags:
- '*'
jobs:
build-gitian:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
operating-system:
- name: "Linux"
option: "l"
- name: "Windows"
option: "w"
- name: "Android"
option: "a"
- name: "FreeBSD"
option: "f"
- name: "macOS"
option: "m"
name: ${{ matrix.operating-system.name }}
steps:
- name: prepare
run: |
sudo apt update
curl -O https://raw.githubusercontent.com/monero-project/monero/${{ github.ref_name }}/contrib/gitian/gitian-build.py
chmod +x gitian-build.py
- name: setup
run: |
./gitian-build.py --setup --docker github-actions ${{ github.ref_name }}
- name: build
run: |
./gitian-build.py --docker --detach-sign --no-commit --build -j 3 -o ${{ matrix.operating-system.option }} github-actions ${{ github.ref_name }}
- name: post build
run: |
cd out/${{ github.ref_name }}
shasum -a256 *
echo \`\`\` >> $GITHUB_STEP_SUMMARY
shasum -a256 * >> $GITHUB_STEP_SUMMARY
echo \`\`\` >> $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v3
with:
name: ${{ matrix.operating-system.name }}
path: |
out/${{ github.ref_name }}/*
+13 -1
View File
@@ -794,7 +794,7 @@ else()
set(USE_LTO_DEFAULT false)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,10485760")
if(NOT BUILD_64)
add_definitions(-DWINVER=0x0501 -D_WIN32_WINNT=0x0501)
add_definitions(-DWINVER=0x0600 -D_WIN32_WINNT=0x0600)
endif()
endif()
set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wold-style-definition -Wstrict-prototypes")
@@ -1178,6 +1178,9 @@ 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)
if(NOT ZMQ_INCLUDE_PATH)
message(FATAL_ERROR "Could not find required header zmq.h")
@@ -1200,6 +1203,15 @@ endif()
if(SODIUM_LIBRARY)
set(ZMQ_LIB "${ZMQ_LIB};${SODIUM_LIBRARY}")
endif()
if(BSD_LIBRARY)
set(ZMQ_LIB "${ZMQ_LIB};${BSD_LIBRARY}")
endif()
if(MD_LIBRARY)
set(ZMQ_LIB "${ZMQ_LIB};${MD_LIBRARY}")
endif()
if(PROTOKIT_LIBRARY)
set(ZMQ_LIB "${ZMQ_LIB};${PROTOKIT_LIBRARY}")
endif()
include(external/supercop/functions.cmake) # place after setting flags and before src directory inclusion
add_subdirectory(contrib)
+5 -5
View File
@@ -138,8 +138,8 @@ Dates are provided in the format YYYY-MM-DD.
| 1978433 | 2019-11-30 | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.3.2 | New CLSAG transaction format
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.3.2 | forbid old MLSAG transaction format
| 2688888 | 2022-08-13 | v15 | v0.18.0.0 | v0.18.1.2 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm
| 2689608 | 2022-08-14 | v16 | v0.18.0.0 | v0.18.1.2 | forbid old v14 transaction format
| 2688888 | 2022-08-13 | v15 | v0.18.0.0 | v0.18.2.2 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm
| 2689608 | 2022-08-14 | v16 | v0.18.0.0 | v0.18.2.2 | forbid old v14 transaction format
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
X's indicate that these details have not been determined as of commit date.
@@ -344,7 +344,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```bash
git clone https://github.com/monero-project/monero.git
cd monero
git checkout v0.18.1.2
git checkout v0.18.2.2
```
* Build:
@@ -463,10 +463,10 @@ application.
cd monero
```
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.18.1.2'. If you don't care about the version and just want binaries from master, skip this step:
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.18.2.2'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.18.1.2
git checkout v0.18.2.2
```
* If you are on a 64-bit system, run:
+1 -1
View File
@@ -113,7 +113,7 @@ if ( LibUSB_FOUND )
if (APPLE OR LibUSB_VERSION_1.0.16 OR STATIC)
if (APPLE)
if(DEPENDS)
list(APPEND TEST_COMPILE_EXTRA_LIBRARIES "-framework Foundation -framework IOKit")
list(APPEND TEST_COMPILE_EXTRA_LIBRARIES "-framework Foundation -framework IOKit -framework Security")
else()
find_library(COREFOUNDATION CoreFoundation)
find_library(IOKIT IOKit)
+4 -1
View File
@@ -143,8 +143,11 @@ $(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig
$(1)_config_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_build_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_stage_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_autoconf=./configure --host=$($($(1)_type)_host) --disable-dependency-tracking --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)"
$(1)_autoconf=./configure --host=$($($(1)_type)_host) --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)"
ifneq ($(1),libusb)
$(1)_autoconf += --disable-dependency-tracking
endif
ifneq ($($(1)_nm),)
$(1)_autoconf += NM="$$($(1)_nm)"
endif
+3 -3
View File
@@ -1,8 +1,8 @@
package=hidapi
$(package)_version=0.11.0
$(package)_download_path=https://github.com/libusb/hidapi/archive
$(package)_version=0.13.1
$(package)_download_path=https://github.com/libusb/hidapi/archive/refs/tags
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=391d8e52f2d6a5cf76e2b0c079cfefe25497ba1d4659131297081fc0cd744632
$(package)_sha256_hash=476a2c9a4dc7d1fc97dd223b84338dbea3809a84caea2dcd887d9778725490e3
$(package)_linux_dependencies=libusb eudev
$(package)_patches=missing_win_include.patch
+3 -3
View File
@@ -1,8 +1,8 @@
package=libusb
$(package)_version=1.0.22
$(package)_download_path=https://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-$($(package)_version)/
$(package)_version=1.0.26
$(package)_download_path=https://github.com/libusb/libusb/releases/download/v$($(package)_version)
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=75aeb9d59a4fdb800d329a545c2e6799f732362193b465ea198f2aa275518157
$(package)_sha256_hash=12ce7a61fc9854d1d2a1ffe095f7b5fac19ddba095c259e6067a46500381b5a5
define $(package)_preprocess_cmds
autoreconf -i
+3 -5
View File
@@ -1,9 +1,8 @@
package=openssl
$(package)_version=1.1.1l
$(package)_version=1.1.1t
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=0b7a3e5e59c34827fe0c3a74b7ec8baef302b98fa80088d7f9153aa16fa76bd1
$(package)_patches=fix_darwin.patch
$(package)_sha256_hash=8dee9b24bdb1dcbf0c3d1e9b02fb8f6bf22165e807f45adeb7c9677536859d3b
define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
@@ -50,8 +49,7 @@ $(package)_config_opts_x86_64_freebsd=BSD-x86_64
endef
define $(package)_preprocess_cmds
sed -i.old 's|"engines", "apps", "test", "util", "tools", "fuzz"|"engines", "tools"|' Configure && \
patch -p1 < $($(package)_patch_dir)/fix_darwin.patch
sed -i.old 's|"engines", "apps", "test", "util", "tools", "fuzz"|"engines", "tools"|' Configure
endef
define $(package)_config_cmds
@@ -1,60 +0,0 @@
From 96ac8f13f4d0ee96baf5724d9f96c44c34b8606c Mon Sep 17 00:00:00 2001
From: David Carlier <devnexen@gmail.com>
Date: Tue, 24 Aug 2021 22:40:14 +0100
Subject: [PATCH] Darwin platform allows to build on releases before
Yosemite/ios 8.
issue #16407 #16408
Reviewed-by: Paul Dale <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/16409)
---
crypto/rand/rand_unix.c | 5 +----
include/crypto/rand.h | 10 ++++++++++
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/crypto/rand/rand_unix.c b/crypto/rand/rand_unix.c
index 43f1069d151d..0f4525106af7 100644
--- a/crypto/rand/rand_unix.c
+++ b/crypto/rand/rand_unix.c
@@ -34,9 +34,6 @@
#if defined(__OpenBSD__)
# include <sys/param.h>
#endif
-#if defined(__APPLE__)
-# include <CommonCrypto/CommonRandom.h>
-#endif
#if defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__)
# include <sys/types.h>
@@ -381,7 +378,7 @@ static ssize_t syscall_random(void *buf, size_t buflen)
if (errno != ENOSYS)
return -1;
}
-# elif defined(__APPLE__)
+# elif defined(OPENSSL_APPLE_CRYPTO_RANDOM)
if (CCRandomGenerateBytes(buf, buflen) == kCCSuccess)
return (ssize_t)buflen;
diff --git a/include/crypto/rand.h b/include/crypto/rand.h
index 5350d3a93119..674f840fd13c 100644
--- a/include/crypto/rand.h
+++ b/include/crypto/rand.h
@@ -20,6 +20,16 @@
# include <openssl/rand.h>
+# if defined(__APPLE__) && !defined(OPENSSL_NO_APPLE_CRYPTO_RANDOM)
+# include <Availability.h>
+# if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000) || \
+ (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000)
+# define OPENSSL_APPLE_CRYPTO_RANDOM 1
+# include <CommonCrypto/CommonCryptoError.h>
+# include <CommonCrypto/CommonRandom.h>
+# endif
+# endif
+
/* forward declaration */
typedef struct rand_pool_st RAND_POOL;
+1 -1
View File
@@ -49,7 +49,7 @@ namespace serialization
byte_stream ss;
ss.reserve(initial_buffer_size);
store_to_binary(ss);
target = epee::byte_slice{std::move(ss)};
target = epee::byte_slice{std::move(ss), false};
return true;
CATCH_ENTRY("portable_storage::store_to_binary", false);
}
+1 -1
View File
@@ -57,7 +57,7 @@ The dockrun.sh script will do everything to build the binaries. Just specify the
version to build as its only argument, e.g.
```bash
VERSION=v0.18.1.2
VERSION=v0.18.2.2
./dockrun.sh $VERSION
```
+1 -1
View File
@@ -133,7 +133,7 @@ Common setup part:
su - gitianuser
GH_USER=YOUR_GITHUB_USER_NAME
VERSION=v0.18.1.2
VERSION=v0.18.2.2
```
Where `GH_USER` is your GitHub user name and `VERSION` is the version tag you want to build.
+83 -74
View File
@@ -46,6 +46,77 @@ using namespace cryptonote;
static bool stop_requested = false;
static bool do_inputs, do_outputs, do_ringsize, do_hours, do_emission, do_fees, do_diff;
static struct tm prevtm, currtm;
static uint64_t prevsz, currsz;
static uint64_t prevtxs, currtxs;
static uint64_t currblks;
static uint64_t h;
static uint64_t totins, totouts, totrings;
static boost::multiprecision::uint128_t prevemission, prevfees;
static boost::multiprecision::uint128_t emission, fees;
static boost::multiprecision::uint128_t totdiff, mindiff, maxdiff;
#define MAX_INOUT 0xffffffff
#define MAX_RINGS 0xffffffff
static uint32_t minins = MAX_INOUT, maxins;
static uint32_t minouts = MAX_INOUT, maxouts;
static uint32_t minrings = MAX_RINGS, maxrings;
static uint32_t io, tottxs;
static uint32_t txhr[24];
static void doprint()
{
char timebuf[64];
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d", &prevtm);
prevtm = currtm;
std::cout << timebuf << "\t" << currblks << "\t" << h << "\t" << currtxs << "\t" << prevtxs + currtxs << "\t" << currsz << "\t" << prevsz + currsz;
prevsz += currsz;
currsz = 0;
prevtxs += currtxs;
currtxs = 0;
if (!tottxs)
tottxs = 1;
if (do_emission) {
std::cout << "\t" << print_money(emission) << "\t" << print_money(prevemission + emission);
prevemission += emission;
emission = 0;
}
if (do_fees) {
std::cout << "\t" << print_money(fees) << "\t" << print_money(prevfees + fees);
prevfees += fees;
fees = 0;
}
if (do_diff) {
std::cout << "\t" << (maxdiff ? mindiff : 0) << "\t" << maxdiff << "\t" << totdiff / currblks;
mindiff = 0; maxdiff = 0; totdiff = 0;
}
if (do_inputs) {
std::cout << "\t" << (maxins ? minins : 0) << "\t" << maxins << "\t" << totins * 1.0 / tottxs;
minins = MAX_INOUT; maxins = 0; totins = 0;
}
if (do_outputs) {
std::cout << "\t" << (maxouts ? minouts : 0) << "\t" << maxouts << "\t" << totouts * 1.0 / tottxs;
minouts = MAX_INOUT; maxouts = 0; totouts = 0;
}
if (do_ringsize) {
std::cout << "\t" << (maxrings ? minrings : 0) << "\t" << maxrings << "\t" << totrings * 1.0 / tottxs;
minrings = MAX_RINGS; maxrings = 0; totrings = 0;
}
if (do_hours) {
for (int i=0; i<24; i++) {
std::cout << "\t" << txhr[i];
txhr[i] = 0;
}
}
currblks = 0;
tottxs = 0;
std::cout << ENDL;
}
int main(int argc, char* argv[])
{
TRY_ENTRY();
@@ -123,13 +194,13 @@ int main(int argc, char* argv[])
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);
bool do_inputs = command_line::get_arg(vm, arg_inputs);
bool do_outputs = command_line::get_arg(vm, arg_outputs);
bool do_ringsize = command_line::get_arg(vm, arg_ringsize);
bool do_hours = command_line::get_arg(vm, arg_hours);
bool do_emission = command_line::get_arg(vm, arg_emission);
bool do_fees = command_line::get_arg(vm, arg_fees);
bool do_diff = command_line::get_arg(vm, arg_diff);
do_inputs = command_line::get_arg(vm, arg_inputs);
do_outputs = command_line::get_arg(vm, arg_outputs);
do_ringsize = command_line::get_arg(vm, arg_ringsize);
do_hours = command_line::get_arg(vm, arg_hours);
do_emission = command_line::get_arg(vm, arg_emission);
do_fees = command_line::get_arg(vm, arg_fees);
do_diff = command_line::get_arg(vm, arg_diff);
LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
std::unique_ptr<Blockchain> core_storage;
@@ -211,25 +282,7 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
}
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;
uint64_t totins = 0, totouts = 0, totrings = 0;
boost::multiprecision::uint128_t prevemission = 0, prevfees = 0;
boost::multiprecision::uint128_t emission = 0, fees = 0;
boost::multiprecision::uint128_t totdiff = 0, mindiff = 0, maxdiff = 0;
uint32_t minins = MAX_INOUT, maxins = 0;
uint32_t minouts = MAX_INOUT, maxouts = 0;
uint32_t minrings = MAX_RINGS, maxrings = 0;
uint32_t io, tottxs = 0;
uint32_t txhr[24] = {0};
unsigned int i;
for (uint64_t h = block_start; h < block_stop; ++h)
for (h = block_start; h < block_stop; ++h)
{
cryptonote::blobdata bd = db->get_block_blob_from_height(h);
cryptonote::block blk;
@@ -239,7 +292,6 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
return 1;
}
time_t tt = blk.timestamp;
char timebuf[64];
epee::misc_utils::get_gmt_time(tt, currtm);
if (!prevtm.tm_year)
prevtm = currtm;
@@ -247,54 +299,9 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
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", &prevtm);
prevtm = currtm;
std::cout << timebuf << "\t" << currblks << "\t" << h << "\t" << currtxs << "\t" << prevtxs + currtxs << "\t" << currsz << "\t" << prevsz + currsz;
prevsz += currsz;
currsz = 0;
prevtxs += currtxs;
currtxs = 0;
if (!tottxs)
tottxs = 1;
if (do_emission) {
std::cout << "\t" << print_money(emission) << "\t" << print_money(prevemission + emission);
prevemission += emission;
emission = 0;
}
if (do_fees) {
std::cout << "\t" << print_money(fees) << "\t" << print_money(prevfees + fees);
prevfees += fees;
fees = 0;
}
if (do_diff) {
std::cout << "\t" << (maxdiff ? mindiff : 0) << "\t" << maxdiff << "\t" << totdiff / currblks;
mindiff = 0; maxdiff = 0; totdiff = 0;
}
if (do_inputs) {
std::cout << "\t" << (maxins ? minins : 0) << "\t" << maxins << "\t" << totins * 1.0 / tottxs;
minins = MAX_INOUT; maxins = 0; totins = 0;
}
if (do_outputs) {
std::cout << "\t" << (maxouts ? minouts : 0) << "\t" << maxouts << "\t" << totouts * 1.0 / tottxs;
minouts = MAX_INOUT; maxouts = 0; totouts = 0;
}
if (do_ringsize) {
std::cout << "\t" << (maxrings ? minrings : 0) << "\t" << maxrings << "\t" << totrings * 1.0 / tottxs;
minrings = MAX_RINGS; maxrings = 0; totrings = 0;
}
if (do_hours) {
for (i=0; i<24; i++) {
std::cout << "\t" << txhr[i];
txhr[i] = 0;
}
}
currblks = 0;
tottxs = 0;
std::cout << ENDL;
if (!(prevtm.tm_mday == 1 && currtm.tm_mday > 27))
doprint();
}
skip:
currsz += bd.size();
uint64_t coinbase_amount;
uint64_t tx_fee_amount = 0;
@@ -371,6 +378,8 @@ skip:
if (stop_requested)
break;
}
if (currblks)
doprint();
core_storage->deinit();
return 0;
Binary file not shown.
+3
View File
@@ -243,6 +243,9 @@ namespace cryptonote
ADD_CHECKPOINT2(2677000, "1b9fee6246eeb176bd17d637bf252e9af54a4218675f01b4449cc0901867f9eb", "0x2f165bc1a5163ba");
ADD_CHECKPOINT2(2706000, "d8eb144c5e1fe6b329ecc900ec95e7792fccff84175fb23a25ed59d7299a511c", "0x310f7d89372f705");
ADD_CHECKPOINT2(2720000, "b19fb41dff15bd1016afbee9f8469f05aab715c9e5d1b974466a11fd58ecbb86", "0x3216b5851ddbb61");
ADD_CHECKPOINT2(2817000, "39726d19ccaac01d150bec827b877ffae710b516bd633503662036ef4422e577", "0x3900669561954c1");
ADD_CHECKPOINT2(2844000, "28fc7b446dfef5b469f5778eb72ddf32a307a5f5a9823d1c394e772349e05d40", "0x3af384ec0e97d12");
ADD_CHECKPOINT2(2851000, "5bf0e47fc782263191a33f63a67db6c711781dc2a3c442e17ed901ec401be5c9", "0x3b6cd8a8ed610e8");
return true;
}
+65
View File
@@ -0,0 +1,65 @@
// Copyright (c) 2014-2022, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <unordered_set>
#include <mutex>
namespace tools
{
template<typename T, size_t MAX_SIZE>
class data_cache
{
public:
void add(const T& value)
{
std::lock_guard<std::mutex> lock(m);
if (data.insert(value).second)
{
T& old_value = buf[counter++ % MAX_SIZE];
data.erase(old_value);
old_value = value;
}
}
bool has(const T& value) const
{
std::lock_guard<std::mutex> lock(m);
return (data.find(value) != data.end());
}
private:
mutable std::mutex m;
std::unordered_set<T> data;
T buf[MAX_SIZE] = {};
size_t counter = 0;
};
}
+2 -15
View File
@@ -30,6 +30,8 @@
// check local first (in the event of static or in-source compilation of libunbound)
#include "unbound.h"
#include <deque>
#include <set>
#include <stdlib.h>
#include "include_base_utils.h"
#include "common/threadpool.h"
@@ -327,11 +329,6 @@ std::vector<std::string> DNSResolver::get_record(const std::string& url, int rec
dnssec_available = false;
dnssec_valid = false;
if (!check_address_syntax(url.c_str()))
{
return addresses;
}
// destructor takes care of cleanup
ub_result_ptr result;
@@ -414,16 +411,6 @@ DNSResolver DNSResolver::create()
return DNSResolver();
}
bool DNSResolver::check_address_syntax(const char *addr) const
{
// if string doesn't contain a dot, we won't consider it a url for now.
if (strchr(addr,'.') == NULL)
{
return false;
}
return true;
}
namespace dns_utils
{
-9
View File
@@ -159,15 +159,6 @@ private:
// TODO: modify this to accommodate DNSSEC
std::vector<std::string> get_record(const std::string& url, int record_type, boost::optional<std::string> (*reader)(const char *,size_t), bool& dnssec_available, bool& dnssec_valid);
/**
* @brief Checks a string to see if it looks like a URL
*
* @param addr the string to be checked
*
* @return true if it looks enough like a URL, false if not
*/
bool check_address_syntax(const char *addr) const;
DNSResolverData *m_data;
}; // class DNSResolver
+1
View File
@@ -31,6 +31,7 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <cstddef>
#include <deque>
#include <functional>
#include <utility>
#include <vector>
+29 -17
View File
@@ -30,29 +30,41 @@
#pragma once
#ifdef _WIN32
#include <windows.h>
#define CTHR_MUTEX_TYPE HANDLE
#define CTHR_MUTEX_INIT NULL
#define CTHR_MUTEX_LOCK(x) do { if (x == NULL) { \
HANDLE p = CreateMutex(NULL, FALSE, NULL); \
if (InterlockedCompareExchangePointer((PVOID*)&x, (PVOID)p, NULL) != NULL) \
CloseHandle(p); \
} WaitForSingleObject(x, INFINITE); } while(0)
#define CTHR_MUTEX_UNLOCK(x) ReleaseMutex(x)
#define CTHR_RWLOCK_TYPE SRWLOCK
#define CTHR_RWLOCK_INIT SRWLOCK_INIT
#define CTHR_RWLOCK_LOCK_WRITE(x) AcquireSRWLockExclusive(&x)
#define CTHR_RWLOCK_UNLOCK_WRITE(x) ReleaseSRWLockExclusive(&x)
#define CTHR_RWLOCK_LOCK_READ(x) AcquireSRWLockShared(&x)
#define CTHR_RWLOCK_UNLOCK_READ(x) ReleaseSRWLockShared(&x)
#define CTHR_RWLOCK_TRYLOCK_READ(x) TryAcquireSRWLockShared(&x)
#define CTHR_THREAD_TYPE HANDLE
#define CTHR_THREAD_RTYPE void
#define CTHR_THREAD_RETURN return
#define CTHR_THREAD_CREATE(thr, func, arg) thr = (HANDLE)_beginthread(func, 0, arg)
#define CTHR_THREAD_JOIN(thr) WaitForSingleObject(thr, INFINITE)
#define CTHR_THREAD_RTYPE unsigned __stdcall
#define CTHR_THREAD_RETURN _endthreadex(0); return 0;
#define CTHR_THREAD_CREATE(thr, func, arg) ((thr = (HANDLE)_beginthreadex(0, 0, func, arg, 0, 0)) != 0L)
#define CTHR_THREAD_JOIN(thr) do { WaitForSingleObject(thr, INFINITE); CloseHandle(thr); } while(0)
#define CTHR_THREAD_CLOSE(thr) CloseHandle((HANDLE)thr);
#else
#include <pthread.h>
#define CTHR_MUTEX_TYPE pthread_mutex_t
#define CTHR_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
#define CTHR_MUTEX_LOCK(x) pthread_mutex_lock(&x)
#define CTHR_MUTEX_UNLOCK(x) pthread_mutex_unlock(&x)
#define CTHR_RWLOCK_TYPE pthread_rwlock_t
#define CTHR_RWLOCK_INIT PTHREAD_RWLOCK_INITIALIZER
#define CTHR_RWLOCK_LOCK_WRITE(x) pthread_rwlock_wrlock(&x)
#define CTHR_RWLOCK_UNLOCK_WRITE(x) pthread_rwlock_unlock(&x)
#define CTHR_RWLOCK_LOCK_READ(x) pthread_rwlock_rdlock(&x)
#define CTHR_RWLOCK_UNLOCK_READ(x) pthread_rwlock_unlock(&x)
#define CTHR_RWLOCK_TRYLOCK_READ(x) (pthread_rwlock_tryrdlock(&x) == 0)
#define CTHR_THREAD_TYPE pthread_t
#define CTHR_THREAD_RTYPE void *
#define CTHR_THREAD_RETURN return NULL
#define CTHR_THREAD_CREATE(thr, func, arg) pthread_create(&thr, NULL, func, arg)
#define CTHR_THREAD_CREATE(thr, func, arg) (pthread_create(&thr, NULL, func, arg) == 0)
#define CTHR_THREAD_JOIN(thr) pthread_join(thr, NULL)
#define CTHR_THREAD_CLOSE(thr)
#endif
+6 -2
View File
@@ -97,5 +97,9 @@ void rx_slow_hash_allocate_state(void);
void rx_slow_hash_free_state(void);
uint64_t rx_seedheight(const uint64_t height);
void rx_seedheights(const uint64_t height, uint64_t *seed_height, uint64_t *next_height);
void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length, char *hash, int miners, int is_alt);
void rx_reorg(const uint64_t split_height);
void rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads);
void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash);
void rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads);
uint32_t rx_get_miner_thread(void);
+332 -185
View File
@@ -43,32 +43,41 @@
#define RX_LOGCAT "randomx"
// Report large page allocation failures as debug messages
#define alloc_err_msg(x) mdebug(RX_LOGCAT, x);
static CTHR_RWLOCK_TYPE main_dataset_lock = CTHR_RWLOCK_INIT;
static CTHR_RWLOCK_TYPE main_cache_lock = CTHR_RWLOCK_INIT;
static randomx_dataset *main_dataset = NULL;
static randomx_cache *main_cache = NULL;
static char main_seedhash[HASH_SIZE];
static int main_seedhash_set = 0;
static CTHR_RWLOCK_TYPE secondary_cache_lock = CTHR_RWLOCK_INIT;
static randomx_cache *secondary_cache = NULL;
static char secondary_seedhash[HASH_SIZE];
static int secondary_seedhash_set = 0;
#if defined(_MSC_VER)
#define THREADV __declspec(thread)
#else
#define THREADV __thread
#endif
typedef struct rx_state {
CTHR_MUTEX_TYPE rs_mutex;
char rs_hash[HASH_SIZE];
uint64_t rs_height;
randomx_cache *rs_cache;
} rx_state;
static THREADV randomx_vm *main_vm_full = NULL;
static THREADV randomx_vm *main_vm_light = NULL;
static THREADV randomx_vm *secondary_vm_light = NULL;
static CTHR_MUTEX_TYPE rx_mutex = CTHR_MUTEX_INIT;
static CTHR_MUTEX_TYPE rx_dataset_mutex = CTHR_MUTEX_INIT;
static THREADV uint32_t miner_thread = 0;
static rx_state rx_s[2] = {{CTHR_MUTEX_INIT,{0},0,0},{CTHR_MUTEX_INIT,{0},0,0}};
static randomx_dataset *rx_dataset;
static int rx_dataset_nomem;
static int rx_dataset_nolp;
static uint64_t rx_dataset_height;
static THREADV randomx_vm *rx_vm = NULL;
static bool is_main(const char* seedhash) { return main_seedhash_set && (memcmp(seedhash, main_seedhash, HASH_SIZE) == 0); }
static bool is_secondary(const char* seedhash) { return secondary_seedhash_set && (memcmp(seedhash, secondary_seedhash, HASH_SIZE) == 0); }
static void local_abort(const char *msg)
{
merror(RX_LOGCAT, "%s", msg);
fprintf(stderr, "%s\n", msg);
#ifdef NDEBUG
_exit(1);
@@ -77,6 +86,16 @@ static void local_abort(const char *msg)
#endif
}
static void hash2hex(const char* hash, char* hex) {
const char* d = "0123456789abcdef";
for (int i = 0; i < HASH_SIZE; ++i) {
const uint8_t b = hash[i];
hex[i * 2 + 0] = d[b >> 4];
hex[i * 2 + 1] = d[b & 15];
}
hex[HASH_SIZE * 2] = '\0';
}
static inline int disabled_flags(void) {
static int flags = -1;
@@ -157,19 +176,6 @@ static unsigned int get_seedhash_epoch_blocks(void)
return blocks;
}
void rx_reorg(const uint64_t split_height) {
int i;
CTHR_MUTEX_LOCK(rx_mutex);
for (i=0; i<2; i++) {
if (split_height <= rx_s[i].rs_height) {
if (rx_s[i].rs_height == rx_dataset_height)
rx_dataset_height = 1;
rx_s[i].rs_height = 1; /* set to an invalid seed height */
}
}
CTHR_MUTEX_UNLOCK(rx_mutex);
}
uint64_t rx_seedheight(const uint64_t height) {
const uint64_t seedhash_epoch_lag = get_seedhash_epoch_lag();
const uint64_t seedhash_epoch_blocks = get_seedhash_epoch_blocks();
@@ -183,6 +189,103 @@ void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nexth
*nextheight = rx_seedheight(height + get_seedhash_epoch_lag());
}
static void rx_alloc_dataset(randomx_flags flags, randomx_dataset** dataset, int ignore_env)
{
if (*dataset) {
return;
}
if (disabled_flags() & RANDOMX_FLAG_FULL_MEM) {
static int shown = 0;
if (!shown) {
shown = 1;
minfo(RX_LOGCAT, "RandomX dataset is disabled by MONERO_RANDOMX_UMASK environment variable.");
}
return;
}
if (!ignore_env && !getenv("MONERO_RANDOMX_FULL_MEM")) {
static int shown = 0;
if (!shown) {
shown = 1;
minfo(RX_LOGCAT, "RandomX dataset is not enabled by default. Use MONERO_RANDOMX_FULL_MEM environment variable to enable it.");
}
return;
}
*dataset = randomx_alloc_dataset((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags());
if (!*dataset) {
alloc_err_msg("Couldn't allocate RandomX dataset using large pages");
*dataset = randomx_alloc_dataset(flags & ~disabled_flags());
if (!*dataset) {
merror(RX_LOGCAT, "Couldn't allocate RandomX dataset");
}
}
}
static void rx_alloc_cache(randomx_flags flags, randomx_cache** cache)
{
if (*cache) {
return;
}
*cache = randomx_alloc_cache((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags());
if (!*cache) {
alloc_err_msg("Couldn't allocate RandomX cache using large pages");
*cache = randomx_alloc_cache(flags & ~disabled_flags());
if (!*cache) local_abort("Couldn't allocate RandomX cache");
}
}
static void rx_init_full_vm(randomx_flags flags, randomx_vm** vm)
{
if (*vm || !main_dataset || (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) {
return;
}
if ((flags & RANDOMX_FLAG_JIT) && !miner_thread) {
flags |= RANDOMX_FLAG_SECURE;
}
*vm = randomx_create_vm((flags | RANDOMX_FLAG_LARGE_PAGES | RANDOMX_FLAG_FULL_MEM) & ~disabled_flags(), NULL, main_dataset);
if (!*vm) {
static int shown = 0;
if (!shown) {
shown = 1;
alloc_err_msg("Couldn't allocate RandomX full VM using large pages (will print only once)");
}
*vm = randomx_create_vm((flags | RANDOMX_FLAG_FULL_MEM) & ~disabled_flags(), NULL, main_dataset);
if (!*vm) {
merror(RX_LOGCAT, "Couldn't allocate RandomX full VM");
}
}
}
static void rx_init_light_vm(randomx_flags flags, randomx_vm** vm, randomx_cache* cache)
{
if (*vm) {
randomx_vm_set_cache(*vm, cache);
return;
}
if ((flags & RANDOMX_FLAG_JIT) && !miner_thread) {
flags |= RANDOMX_FLAG_SECURE;
}
flags &= ~RANDOMX_FLAG_FULL_MEM;
*vm = randomx_create_vm((flags | RANDOMX_FLAG_LARGE_PAGES) & ~disabled_flags(), cache, NULL);
if (!*vm) {
static int shown = 0;
if (!shown) {
shown = 1;
alloc_err_msg("Couldn't allocate RandomX light VM using large pages (will print only once)");
}
*vm = randomx_create_vm(flags & ~disabled_flags(), cache, NULL);
if (!*vm) local_abort("Couldn't allocate RandomX light VM");
}
}
typedef struct seedinfo {
randomx_cache *si_cache;
unsigned long si_start;
@@ -191,187 +294,231 @@ typedef struct seedinfo {
static CTHR_THREAD_RTYPE rx_seedthread(void *arg) {
seedinfo *si = arg;
randomx_init_dataset(rx_dataset, si->si_cache, si->si_start, si->si_count);
randomx_init_dataset(main_dataset, si->si_cache, si->si_start, si->si_count);
CTHR_THREAD_RETURN;
}
static void rx_initdata(randomx_cache *rs_cache, const int miners, const uint64_t seedheight) {
if (miners > 1) {
unsigned long delta = randomx_dataset_item_count() / miners;
unsigned long start = 0;
int i;
seedinfo *si;
CTHR_THREAD_TYPE *st;
si = malloc(miners * sizeof(seedinfo));
if (si == NULL)
local_abort("Couldn't allocate RandomX mining threadinfo");
st = malloc(miners * sizeof(CTHR_THREAD_TYPE));
if (st == NULL) {
free(si);
local_abort("Couldn't allocate RandomX mining threadlist");
}
for (i=0; i<miners-1; i++) {
si[i].si_cache = rs_cache;
si[i].si_start = start;
si[i].si_count = delta;
start += delta;
}
si[i].si_cache = rs_cache;
static void rx_init_dataset(size_t max_threads) {
if (!main_dataset) {
return;
}
// leave 2 CPU cores for other tasks
const size_t num_threads = (max_threads < 4) ? 1 : (max_threads - 2);
seedinfo* si = malloc(num_threads * sizeof(seedinfo));
if (!si) local_abort("Couldn't allocate RandomX mining threadinfo");
const uint32_t delta = randomx_dataset_item_count() / num_threads;
uint32_t start = 0;
const size_t n1 = num_threads - 1;
for (size_t i = 0; i < n1; ++i) {
si[i].si_cache = main_cache;
si[i].si_start = start;
si[i].si_count = randomx_dataset_item_count() - start;
for (i=1; i<miners; i++) {
CTHR_THREAD_CREATE(st[i], rx_seedthread, &si[i]);
}
randomx_init_dataset(rx_dataset, rs_cache, 0, si[0].si_count);
for (i=1; i<miners; i++) {
CTHR_THREAD_JOIN(st[i]);
}
free(st);
free(si);
} else {
randomx_init_dataset(rx_dataset, rs_cache, 0, randomx_dataset_item_count());
si[i].si_count = delta;
start += delta;
}
rx_dataset_height = seedheight;
si[n1].si_cache = main_cache;
si[n1].si_start = start;
si[n1].si_count = randomx_dataset_item_count() - start;
CTHR_THREAD_TYPE *st = malloc(num_threads * sizeof(CTHR_THREAD_TYPE));
if (!st) local_abort("Couldn't allocate RandomX mining threadlist");
CTHR_RWLOCK_LOCK_READ(main_cache_lock);
for (size_t i = 0; i < n1; ++i) {
if (!CTHR_THREAD_CREATE(st[i], rx_seedthread, &si[i])) {
local_abort("Couldn't start RandomX seed thread");
}
}
randomx_init_dataset(main_dataset, si[n1].si_cache, si[n1].si_start, si[n1].si_count);
for (size_t i = 0; i < n1; ++i) CTHR_THREAD_JOIN(st[i]);
CTHR_RWLOCK_UNLOCK_READ(main_cache_lock);
free(st);
free(si);
minfo(RX_LOGCAT, "RandomX dataset initialized");
}
void rx_slow_hash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length,
char *hash, int miners, int is_alt) {
uint64_t s_height = rx_seedheight(mainheight);
int toggle = (s_height & get_seedhash_epoch_blocks()) != 0;
randomx_flags flags = enabled_flags() & ~disabled_flags();
rx_state *rx_sp;
randomx_cache *cache;
typedef struct thread_info {
char seedhash[HASH_SIZE];
size_t max_threads;
} thread_info;
CTHR_MUTEX_LOCK(rx_mutex);
static CTHR_THREAD_RTYPE rx_set_main_seedhash_thread(void *arg) {
thread_info* info = arg;
/* if alt block but with same seed as mainchain, no need for alt cache */
if (is_alt) {
if (s_height == seedheight && !memcmp(rx_s[toggle].rs_hash, seedhash, HASH_SIZE))
is_alt = 0;
} else {
/* RPC could request an earlier block on mainchain */
if (s_height > seedheight)
is_alt = 1;
/* miner can be ahead of mainchain */
else if (s_height < seedheight)
toggle ^= 1;
CTHR_RWLOCK_LOCK_WRITE(main_dataset_lock);
CTHR_RWLOCK_LOCK_WRITE(main_cache_lock);
// Double check that seedhash wasn't already updated
if (is_main(info->seedhash)) {
CTHR_RWLOCK_UNLOCK_WRITE(main_cache_lock);
CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock);
free(info);
CTHR_THREAD_RETURN;
}
memcpy(main_seedhash, info->seedhash, HASH_SIZE);
main_seedhash_set = 1;
char buf[HASH_SIZE * 2 + 1];
hash2hex(main_seedhash, buf);
minfo(RX_LOGCAT, "RandomX new main seed hash is %s", buf);
const randomx_flags flags = enabled_flags() & ~disabled_flags();
rx_alloc_dataset(flags, &main_dataset, 0);
rx_alloc_cache(flags, &main_cache);
randomx_init_cache(main_cache, info->seedhash, HASH_SIZE);
minfo(RX_LOGCAT, "RandomX main cache initialized");
CTHR_RWLOCK_UNLOCK_WRITE(main_cache_lock);
// From this point, rx_slow_hash can calculate hashes in light mode, but dataset is not initialized yet
rx_init_dataset(info->max_threads);
CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock);
free(info);
CTHR_THREAD_RETURN;
}
void rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads) {
// Early out if seedhash didn't change
if (is_main(seedhash)) {
return;
}
toggle ^= (is_alt != 0);
// Update main cache and dataset in the background
thread_info* info = malloc(sizeof(thread_info));
if (!info) local_abort("Couldn't allocate RandomX mining threadinfo");
rx_sp = &rx_s[toggle];
CTHR_MUTEX_LOCK(rx_sp->rs_mutex);
CTHR_MUTEX_UNLOCK(rx_mutex);
memcpy(info->seedhash, seedhash, HASH_SIZE);
info->max_threads = max_dataset_init_threads;
cache = rx_sp->rs_cache;
if (cache == NULL) {
if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES)) {
cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES);
if (cache == NULL) {
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX cache");
}
}
if (cache == NULL) {
cache = randomx_alloc_cache(flags);
if (cache == NULL)
local_abort("Couldn't allocate RandomX cache");
}
CTHR_THREAD_TYPE t;
if (!CTHR_THREAD_CREATE(t, rx_set_main_seedhash_thread, info)) {
local_abort("Couldn't start RandomX seed thread");
}
if (rx_sp->rs_height != seedheight || rx_sp->rs_cache == NULL || memcmp(seedhash, rx_sp->rs_hash, HASH_SIZE)) {
randomx_init_cache(cache, seedhash, HASH_SIZE);
rx_sp->rs_cache = cache;
rx_sp->rs_height = seedheight;
memcpy(rx_sp->rs_hash, seedhash, HASH_SIZE);
}
if (rx_vm == NULL) {
if ((flags & RANDOMX_FLAG_JIT) && !miners) {
flags |= RANDOMX_FLAG_SECURE & ~disabled_flags();
}
if (miners && (disabled_flags() & RANDOMX_FLAG_FULL_MEM)) {
miners = 0;
}
if (miners) {
CTHR_MUTEX_LOCK(rx_dataset_mutex);
if (!rx_dataset_nomem) {
if (rx_dataset == NULL) {
if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES)) {
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES);
if (rx_dataset == NULL) {
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX dataset");
}
}
if (rx_dataset == NULL)
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT);
if (rx_dataset != NULL)
rx_initdata(rx_sp->rs_cache, miners, seedheight);
CTHR_THREAD_CLOSE(t);
}
void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash) {
const randomx_flags flags = enabled_flags() & ~disabled_flags();
int success = 0;
// Fast path (seedhash == main_seedhash)
// Multiple threads can run in parallel in fast or light mode, 1-2 ms or 10-15 ms per hash per thread
if (is_main(seedhash)) {
// If CTHR_RWLOCK_TRYLOCK_READ fails it means dataset is being initialized now, so use the light mode
if (main_dataset && CTHR_RWLOCK_TRYLOCK_READ(main_dataset_lock)) {
// Double check that main_seedhash didn't change
if (is_main(seedhash)) {
rx_init_full_vm(flags, &main_vm_full);
if (main_vm_full) {
randomx_calculate_hash(main_vm_full, data, length, result_hash);
success = 1;
}
}
if (rx_dataset != NULL)
flags |= RANDOMX_FLAG_FULL_MEM;
else {
miners = 0;
if (!rx_dataset_nomem) {
rx_dataset_nomem = 1;
mwarning(RX_LOGCAT, "Couldn't allocate RandomX dataset for miner");
}
CTHR_RWLOCK_UNLOCK_READ(main_dataset_lock);
} else {
CTHR_RWLOCK_LOCK_READ(main_cache_lock);
// Double check that main_seedhash didn't change
if (is_main(seedhash)) {
rx_init_light_vm(flags, &main_vm_light, main_cache);
randomx_calculate_hash(main_vm_light, data, length, result_hash);
success = 1;
}
CTHR_MUTEX_UNLOCK(rx_dataset_mutex);
CTHR_RWLOCK_UNLOCK_READ(main_cache_lock);
}
if (!(disabled_flags() & RANDOMX_FLAG_LARGE_PAGES) && !rx_dataset_nolp) {
rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset);
if(rx_vm == NULL) { //large pages failed
mdebug(RX_LOGCAT, "Couldn't use largePages for RandomX VM");
rx_dataset_nolp = 1;
}
}
if (rx_vm == NULL)
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset);
if(rx_vm == NULL) {//fallback if everything fails
flags = RANDOMX_FLAG_DEFAULT | (miners ? RANDOMX_FLAG_FULL_MEM : 0);
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset);
}
if (rx_vm == NULL)
local_abort("Couldn't allocate RandomX VM");
} else if (miners) {
CTHR_MUTEX_LOCK(rx_dataset_mutex);
if (rx_dataset != NULL && rx_dataset_height != seedheight)
rx_initdata(cache, miners, seedheight);
else if (rx_dataset == NULL) {
/* this is a no-op if the cache hasn't changed */
randomx_vm_set_cache(rx_vm, rx_sp->rs_cache);
}
CTHR_MUTEX_UNLOCK(rx_dataset_mutex);
} else {
/* this is a no-op if the cache hasn't changed */
randomx_vm_set_cache(rx_vm, rx_sp->rs_cache);
}
/* mainchain users can run in parallel */
if (!is_alt)
CTHR_MUTEX_UNLOCK(rx_sp->rs_mutex);
randomx_calculate_hash(rx_vm, data, length, hash);
/* altchain slot users always get fully serialized */
if (is_alt)
CTHR_MUTEX_UNLOCK(rx_sp->rs_mutex);
if (success) {
return;
}
char buf[HASH_SIZE * 2 + 1];
// Slow path (seedhash != main_seedhash, but seedhash == secondary_seedhash)
// Multiple threads can run in parallel in light mode, 10-15 ms per hash per thread
if (!secondary_cache) {
CTHR_RWLOCK_LOCK_WRITE(secondary_cache_lock);
if (!secondary_cache) {
hash2hex(seedhash, buf);
minfo(RX_LOGCAT, "RandomX new secondary seed hash is %s", buf);
rx_alloc_cache(flags, &secondary_cache);
randomx_init_cache(secondary_cache, seedhash, HASH_SIZE);
minfo(RX_LOGCAT, "RandomX secondary cache updated");
memcpy(secondary_seedhash, seedhash, HASH_SIZE);
secondary_seedhash_set = 1;
}
CTHR_RWLOCK_UNLOCK_WRITE(secondary_cache_lock);
}
CTHR_RWLOCK_LOCK_READ(secondary_cache_lock);
if (is_secondary(seedhash)) {
rx_init_light_vm(flags, &secondary_vm_light, secondary_cache);
randomx_calculate_hash(secondary_vm_light, data, length, result_hash);
success = 1;
}
CTHR_RWLOCK_UNLOCK_READ(secondary_cache_lock);
if (success) {
return;
}
// Slowest path (seedhash != main_seedhash, seedhash != secondary_seedhash)
// Only one thread runs at a time and updates secondary_seedhash if needed, up to 200-500 ms per hash
CTHR_RWLOCK_LOCK_WRITE(secondary_cache_lock);
if (!is_secondary(seedhash)) {
hash2hex(seedhash, buf);
minfo(RX_LOGCAT, "RandomX new secondary seed hash is %s", buf);
randomx_init_cache(secondary_cache, seedhash, HASH_SIZE);
minfo(RX_LOGCAT, "RandomX secondary cache updated");
memcpy(secondary_seedhash, seedhash, HASH_SIZE);
secondary_seedhash_set = 1;
}
rx_init_light_vm(flags, &secondary_vm_light, secondary_cache);
randomx_calculate_hash(secondary_vm_light, data, length, result_hash);
CTHR_RWLOCK_UNLOCK_WRITE(secondary_cache_lock);
}
void rx_slow_hash_allocate_state(void) {
void rx_set_miner_thread(uint32_t value, size_t max_dataset_init_threads) {
miner_thread = value;
// If dataset is not allocated yet, try to allocate and initialize it
CTHR_RWLOCK_LOCK_WRITE(main_dataset_lock);
if (main_dataset) {
CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock);
return;
}
const randomx_flags flags = enabled_flags() & ~disabled_flags();
rx_alloc_dataset(flags, &main_dataset, 1);
rx_init_dataset(max_dataset_init_threads);
CTHR_RWLOCK_UNLOCK_WRITE(main_dataset_lock);
}
void rx_slow_hash_free_state(void) {
if (rx_vm != NULL) {
randomx_destroy_vm(rx_vm);
rx_vm = NULL;
uint32_t rx_get_miner_thread() {
return miner_thread;
}
void rx_slow_hash_allocate_state() {}
static void rx_destroy_vm(randomx_vm** vm) {
if (*vm) {
randomx_destroy_vm(*vm);
*vm = NULL;
}
}
void rx_stop_mining(void) {
CTHR_MUTEX_LOCK(rx_dataset_mutex);
if (rx_dataset != NULL) {
randomx_dataset *rd = rx_dataset;
rx_dataset = NULL;
randomx_release_dataset(rd);
}
rx_dataset_nomem = 0;
rx_dataset_nolp = 0;
CTHR_MUTEX_UNLOCK(rx_dataset_mutex);
void rx_slow_hash_free_state() {
rx_destroy_vm(&main_vm_full);
rx_destroy_vm(&main_vm_light);
rx_destroy_vm(&secondary_vm_light);
}
+3 -2
View File
@@ -82,6 +82,7 @@
using namespace epee;
#include "miner.h"
#include "crypto/hash.h"
extern "C" void slow_hash_allocate_state();
@@ -436,7 +437,6 @@ namespace cryptonote
{
m_stop = true;
}
extern "C" void rx_stop_mining(void);
//-----------------------------------------------------------------------------------------------------
bool miner::stop()
{
@@ -469,7 +469,6 @@ namespace cryptonote
MINFO("Mining has been stopped, " << m_threads.size() << " finished" );
m_threads.clear();
m_threads_autodetect.clear();
rx_stop_mining();
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -524,6 +523,8 @@ namespace cryptonote
bool miner::worker_thread()
{
const uint32_t th_local_index = m_thread_index++; // atomically increment, getting value before increment
crypto::rx_set_miner_thread(th_local_index, tools::get_max_concurrency());
MLOG_SET_THREAD_NAME(std::string("[miner ") + std::to_string(th_local_index) + "]");
MGINFO("Miner thread was started ["<< th_local_index << "]");
uint32_t nonce = m_starter_nonce + th_local_index;
+7 -1
View File
@@ -42,7 +42,12 @@ namespace cryptonote
static_assert(unsigned(relay_method::none) == 0, "default m_relay initialization is not to relay_method::none");
relay_method m_relay; // gives indication on how tx should be relayed (if at all)
bool m_verifivation_failed; //bad tx, should drop connection
bool m_verifivation_failed; //bad tx, tx should not enter mempool and connection should be dropped unless m_no_drop_offense
// Do not add to mempool, do not relay, but also do not punish the peer for sending or drop
// connections to them. Used for low fees, tx_extra too big, "relay-only rules". Not to be
// confused with breaking soft fork rules, because tx could be later added to the chain if mined
// because it does not violate consensus rules.
bool m_no_drop_offense;
bool m_verifivation_impossible; //the transaction is related with an alternative blockchain
bool m_added_to_pool;
bool m_low_mixin;
@@ -53,6 +58,7 @@ namespace cryptonote
bool m_overspend;
bool m_fee_too_low;
bool m_too_few_outputs;
bool m_tx_extra_too_big;
};
struct block_verification_context
+6
View File
@@ -206,6 +206,11 @@
#define DNS_BLOCKLIST_LIFETIME (86400 * 8)
//The limit is enough for the mandatory transaction content with 16 outputs (547 bytes),
//a custom tag (1 byte) and up to 32 bytes of custom data for each recipient.
// (1+32) + (1+1+16*32) + (1+16*32) = 1060
#define MAX_TX_EXTRA_SIZE 1060
// New constants are intended to go here
namespace config
{
@@ -248,6 +253,7 @@ namespace config
const unsigned char HASH_KEY_MM_SLOT = 'm';
const constexpr char HASH_KEY_MULTISIG_TX_PRIVKEYS_SEED[] = "multisig_tx_privkeys_seed";
const constexpr char HASH_KEY_MULTISIG_TX_PRIVKEYS[] = "multisig_tx_privkeys";
const constexpr char HASH_KEY_TXHASH_AND_MIXRING[] = "txhash_and_mixring";
// Multisig
const uint32_t MULTISIG_MAX_SIGNERS{16};
+3 -1
View File
@@ -31,7 +31,9 @@ set(cryptonote_core_sources
cryptonote_core.cpp
tx_pool.cpp
tx_sanity_check.cpp
cryptonote_tx_utils.cpp)
cryptonote_tx_utils.cpp
tx_verification_utils.cpp
)
set(cryptonote_core_headers)
+47 -78
View File
@@ -57,6 +57,7 @@
#include "common/notify.h"
#include "common/varint.h"
#include "common/pruning.h"
#include "common/data_cache.h"
#include "time_helper.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
@@ -98,7 +99,8 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
m_difficulty_for_next_block(1),
m_btc_valid(false),
m_batch_success(true),
m_prepare_height(0)
m_prepare_height(0),
m_rct_ver_cache()
{
LOG_PRINT_L3("Blockchain::" << __func__);
}
@@ -456,6 +458,14 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
if (!update_next_cumulative_weight_limit())
return false;
}
if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
{
const crypto::hash seedhash = get_block_id_by_height(crypto::rx_seedheight(m_db->height()));
if (seedhash != crypto::null_hash)
rx_set_main_seedhash(seedhash.data, tools::get_max_concurrency());
}
return true;
}
//------------------------------------------------------------------
@@ -570,6 +580,12 @@ void Blockchain::pop_blocks(uint64_t nblocks)
if (stop_batch)
m_db->batch_stop();
if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
{
const crypto::hash seedhash = get_block_id_by_height(crypto::rx_seedheight(m_db->height()));
rx_set_main_seedhash(seedhash.data, tools::get_max_concurrency());
}
}
//------------------------------------------------------------------
// This function tells BlockchainDB to remove the top block from the
@@ -1239,18 +1255,20 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
}
m_hardfork->reorganize_from_chain_height(split_height);
get_block_longhash_reorg(split_height);
std::shared_ptr<tools::Notify> reorg_notify = m_reorg_notify;
if (reorg_notify)
reorg_notify->notify("%s", std::to_string(split_height).c_str(), "%h", std::to_string(m_db->height()).c_str(),
"%n", std::to_string(m_db->height() - split_height).c_str(), "%d", std::to_string(discarded_blocks).c_str(), NULL);
const uint64_t new_height = m_db->height();
const crypto::hash seedhash = get_block_id_by_height(crypto::rx_seedheight(new_height));
crypto::hash prev_id;
if (!get_block_hash(alt_chain.back().bl, prev_id))
MERROR("Failed to get block hash of an alternative chain's tip");
else
send_miner_notifications(prev_id, alt_chain.back().already_generated_coins);
send_miner_notifications(new_height, seedhash, prev_id, alt_chain.back().already_generated_coins);
for (const auto& notifier : m_block_notifiers)
{
@@ -1262,6 +1280,9 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>
}
}
if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
rx_set_main_seedhash(seedhash.data, tools::get_max_concurrency());
MGINFO_GREEN("REORGANIZE SUCCESS! on height: " << split_height << ", new blockchain size: " << m_db->height());
return true;
}
@@ -2001,7 +2022,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
{
seedhash = get_block_id_by_height(seedheight);
}
get_altblock_longhash(bei.bl, proof_of_work, get_current_blockchain_height(), bei.height, seedheight, seedhash);
get_altblock_longhash(bei.bl, proof_of_work, seedhash);
} else
{
get_block_longhash(this, bei.bl, proof_of_work, bei.height, 0);
@@ -3192,7 +3213,7 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const
}
return false;
}
bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys) const
bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys)
{
PERF_TIMER(expand_transaction_2);
CHECK_AND_ASSERT_MES(tx.version == 2, false, "Transaction version is not 2");
@@ -3515,6 +3536,13 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
false, "Transaction spends at least one output which is too young");
}
// Warn that new RCT types are present, and thus the cache is not being used effectively
static constexpr const std::uint8_t RCT_CACHE_TYPE = rct::RCTTypeBulletproofPlus;
if (tx.rct_signatures.type > RCT_CACHE_TYPE)
{
MWARNING("RCT cache is not caching new verification results. Please update RCT_CACHE_TYPE!");
}
if (tx.version == 1)
{
if (threads > 1)
@@ -3536,12 +3564,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
else
{
if (!expand_transaction_2(tx, tx_prefix_hash, pubkeys))
{
MERROR_VER("Failed to expand rct signatures!");
return false;
}
// from version 2, check ringct signatures
// obviously, the original and simple rct APIs use a mixRing that's indexes
// in opposite orders, because it'd be too simple otherwise...
@@ -3559,61 +3581,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
case rct::RCTTypeCLSAG:
case rct::RCTTypeBulletproofPlus:
{
// check all this, either reconstructed (so should really pass), or not
{
if (pubkeys.size() != rv.mixRing.size())
{
MERROR_VER("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
return false;
}
for (size_t i = 0; i < pubkeys.size(); ++i)
{
if (pubkeys[i].size() != rv.mixRing[i].size())
{
MERROR_VER("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
return false;
}
}
for (size_t n = 0; n < pubkeys.size(); ++n)
{
for (size_t m = 0; m < pubkeys[n].size(); ++m)
{
if (pubkeys[n][m].dest != rct::rct2pk(rv.mixRing[n][m].dest))
{
MERROR_VER("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m);
return false;
}
if (pubkeys[n][m].mask != rct::rct2pk(rv.mixRing[n][m].mask))
{
MERROR_VER("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m);
return false;
}
}
}
}
const size_t n_sigs = rct::is_rct_clsag(rv.type) ? rv.p.CLSAGs.size() : rv.p.MGs.size();
if (n_sigs != tx.vin.size())
{
MERROR_VER("Failed to check ringct signatures: mismatched MGs/vin sizes");
return false;
}
for (size_t n = 0; n < tx.vin.size(); ++n)
{
bool error;
if (rct::is_rct_clsag(rv.type))
error = memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.CLSAGs[n].I, 32);
else
error = rv.p.MGs[n].II.empty() || memcmp(&boost::get<txin_to_key>(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32);
if (error)
{
MERROR_VER("Failed to check ringct signatures: mismatched key image");
return false;
}
}
if (!rct::verRctNonSemanticsSimple(rv))
if (!ver_rct_non_semantics_simple_cached(tx, pubkeys, m_rct_ver_cache, RCT_CACHE_TYPE))
{
MERROR_VER("Failed to check ringct signatures!");
return false;
@@ -3622,6 +3590,12 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
case rct::RCTTypeFull:
{
if (!expand_transaction_2(tx, tx_prefix_hash, pubkeys))
{
MERROR_VER("Failed to expand rct signatures!");
return false;
}
// check all this, either reconstructed (so should really pass), or not
{
bool size_matches = true;
@@ -4552,11 +4526,15 @@ leave:
}
}
send_miner_notifications(id, already_generated_coins);
const crypto::hash seedhash = get_block_id_by_height(crypto::rx_seedheight(new_height));
send_miner_notifications(new_height, seedhash, id, already_generated_coins);
for (const auto& notifier: m_block_notifiers)
notifier(new_height - 1, {std::addressof(bl), 1});
if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
rx_set_main_seedhash(seedhash.data, tools::get_max_concurrency());
return true;
}
//------------------------------------------------------------------
@@ -5604,7 +5582,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "52105e0e45013e4c6705d5b7902268f5989b6eea71f5a04160176297a79f4b32";
static const char expected_block_hashes_hash[] = "2c95b5af1f3ee41893ae0c585fd59207a40f28ed4addbaad64a46a39b82955e7";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
@@ -5761,24 +5739,15 @@ void Blockchain::cache_block_template(const block &b, const cryptonote::account_
m_btc_valid = true;
}
void Blockchain::send_miner_notifications(const crypto::hash &prev_id, uint64_t already_generated_coins)
void Blockchain::send_miner_notifications(uint64_t height, const crypto::hash &seed_hash, const crypto::hash &prev_id, uint64_t already_generated_coins)
{
if (m_miner_notifiers.empty())
return;
const uint64_t height = m_db->height();
const uint8_t major_version = m_hardfork->get_ideal_version(height);
const difficulty_type diff = get_difficulty_for_next_block();
const uint64_t median_weight = m_current_block_cumul_weight_median;
crypto::hash seed_hash = crypto::null_hash;
if (m_hardfork->get_current_version() >= RX_BLOCK_VERSION)
{
uint64_t seed_height, next_height;
crypto::rx_seedheights(height, &seed_height, &next_height);
seed_hash = get_block_id_by_height(seed_height);
}
std::vector<tx_block_template_backlog_entry> tx_backlog;
m_tx_pool.get_block_template_backlog(tx_backlog);
+16 -10
View File
@@ -57,6 +57,7 @@
#include "rpc/core_rpc_server_commands_defs.h"
#include "cryptonote_basic/difficulty.h"
#include "cryptonote_tx_utils.h"
#include "tx_verification_utils.h"
#include "cryptonote_basic/verification_context.h"
#include "crypto/hash.h"
#include "checkpoints/checkpoints.h"
@@ -596,6 +597,15 @@ namespace cryptonote
*/
bool store_blockchain();
/**
* @brief expands v2 transaction data from blockchain
*
* RingCT transactions do not transmit some of their data if it
* can be reconstituted by the receiver. This function expands
* that implicit data.
*/
static bool expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys);
/**
* @brief validates a transaction's inputs
*
@@ -1222,6 +1232,9 @@ namespace cryptonote
uint64_t m_prepare_nblocks;
std::vector<block> *m_prepare_blocks;
// cache for verifying transaction RCT non semantics
mutable rct_ver_cache_t m_rct_ver_cache;
/**
* @brief collects the keys for all outputs being "spent" as an input
*
@@ -1574,15 +1587,6 @@ namespace cryptonote
*/
void load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints);
/**
* @brief expands v2 transaction data from blockchain
*
* RingCT transactions do not transmit some of their data if it
* can be reconstituted by the receiver. This function expands
* that implicit data.
*/
bool expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys) const;
/**
* @brief invalidates any cached block template
*/
@@ -1598,9 +1602,11 @@ namespace cryptonote
/**
* @brief sends new block notifications to ZMQ `miner_data` subscribers
*
* @param height current blockchain height
* @param seed_hash seed hash to use for mining
* @param prev_id hash of new blockchain tip
* @param already_generated_coins total coins mined by the network so far
*/
void send_miner_notifications(const crypto::hash &prev_id, uint64_t already_generated_coins);
void send_miner_notifications(uint64_t height, const crypto::hash &seed_hash, const crypto::hash &prev_id, uint64_t already_generated_coins);
};
} // namespace cryptonote
+1 -1
View File
@@ -1099,7 +1099,7 @@ namespace cryptonote
else if(tvc[i].m_verifivation_impossible)
{MERROR_VER("Transaction verification impossible: " << results[i].hash);}
if(tvc[i].m_added_to_pool)
if(tvc[i].m_added_to_pool && results[i].tx.extra.size() <= MAX_TX_EXTRA_SIZE)
{
MDEBUG("tx added: " << results[i].hash);
valid_events = true;
+8 -20
View File
@@ -437,6 +437,8 @@ namespace cryptonote
if (!sort_tx_extra(tx.extra, tx.extra))
return false;
CHECK_AND_ASSERT_MES(tx.extra.size() <= MAX_TX_EXTRA_SIZE, false, "TX extra size (" << tx.extra.size() << ") is greater than max allowed (" << MAX_TX_EXTRA_SIZE << ")");
//check money
if(summary_outs_money > summary_inputs_money )
{
@@ -669,10 +671,10 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, const uint64_t seed_height, const crypto::hash& seed_hash)
void get_altblock_longhash(const block& b, crypto::hash& res, const crypto::hash& seed_hash)
{
blobdata bd = get_block_hashing_blob(b);
rx_slow_hash(main_height, seed_height, seed_hash.data, bd.data(), bd.size(), res.data, 0, 1);
rx_slow_hash(seed_hash.data, bd.data(), bd.size(), res.data);
}
bool get_block_longhash(const Blockchain *pbc, const blobdata& bd, crypto::hash& res, const uint64_t height, const int major_version, const crypto::hash *seed_hash, const int miners)
@@ -686,20 +688,16 @@ namespace cryptonote
}
if (major_version >= RX_BLOCK_VERSION)
{
uint64_t seed_height, main_height;
crypto::hash hash;
if (pbc != NULL)
{
seed_height = rx_seedheight(height);
const uint64_t seed_height = rx_seedheight(height);
hash = seed_hash ? *seed_hash : pbc->get_pending_block_id_by_height(seed_height);
main_height = pbc->get_current_blockchain_height();
} else
{
memset(&hash, 0, sizeof(hash)); // only happens when generating genesis block
seed_height = 0;
main_height = 0;
}
rx_slow_hash(main_height, seed_height, hash.data, bd.data(), bd.size(), res.data, seed_hash ? 0 : miners, !!seed_hash);
rx_slow_hash(hash.data, bd.data(), bd.size(), res.data);
} else {
const int pow_variant = major_version >= 7 ? major_version - 6 : 0;
crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant, height);
@@ -713,20 +711,10 @@ namespace cryptonote
return get_block_longhash(pbc, bd, res, height, b.major_version, seed_hash, miners);
}
bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const int miners)
{
return get_block_longhash(pbc, b, res, height, NULL, miners);
}
crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const int miners)
crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const crypto::hash *seed_hash, const int miners)
{
crypto::hash p = crypto::null_hash;
get_block_longhash(pbc, b, p, height, miners);
get_block_longhash(pbc, b, p, height, seed_hash, miners);
return p;
}
void get_block_longhash_reorg(const uint64_t split_height)
{
rx_reorg(split_height);
}
}
+4 -8
View File
@@ -144,14 +144,10 @@ namespace cryptonote
);
class Blockchain;
bool get_block_longhash(const Blockchain *pb, const blobdata& bd, crypto::hash& res, const uint64_t height,
const int major_version, const crypto::hash *seed_hash, const int miners);
bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const int miners);
bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const crypto::hash *seed_hash, const int miners);
void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height,
const uint64_t seed_height, const crypto::hash& seed_hash);
crypto::hash get_block_longhash(const Blockchain *pb, const block& b, const uint64_t height, const int miners);
void get_block_longhash_reorg(const uint64_t split_height);
bool get_block_longhash(const Blockchain *pb, const blobdata& bd, crypto::hash& res, const uint64_t height, const int major_version, const crypto::hash *seed_hash, const int miners = 0);
bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const crypto::hash *seed_hash = nullptr, const int miners = 0);
crypto::hash get_block_longhash(const Blockchain *pb, const block& b, const uint64_t height, const crypto::hash *seed_hash = nullptr, const int miners = 0);
void get_altblock_longhash(const block& b, crypto::hash& res, const crypto::hash& seed_hash);
}
+11
View File
@@ -207,6 +207,7 @@ namespace cryptonote
{
tvc.m_verifivation_failed = true;
tvc.m_fee_too_low = true;
tvc.m_no_drop_offense = true;
return false;
}
@@ -219,6 +220,16 @@ namespace cryptonote
return false;
}
size_t tx_extra_size = tx.extra.size();
if (!kept_by_block && tx_extra_size > MAX_TX_EXTRA_SIZE)
{
LOG_PRINT_L1("transaction tx-extra is too big: " << tx_extra_size << " bytes, the limit is: " << MAX_TX_EXTRA_SIZE);
tvc.m_verifivation_failed = true;
tvc.m_tx_extra_too_big = true;
tvc.m_no_drop_offense = true;
return false;
}
// if the transaction came from a block popped from the chain,
// don't check if we have its key images as spent.
// TODO: Investigate why not?
@@ -0,0 +1,167 @@
// Copyright (c) 2023, 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 "cryptonote_core/blockchain.h"
#include "cryptonote_core/tx_verification_utils.h"
#include "ringct/rctSigs.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "blockchain"
#define VER_ASSERT(cond, msgexpr) CHECK_AND_ASSERT_MES(cond, false, msgexpr)
using namespace cryptonote;
// Do RCT expansion, then do post-expansion sanity checks, then do full non-semantics verification.
static bool expand_tx_and_ver_rct_non_sem(transaction& tx, const rct::ctkeyM& mix_ring)
{
// Pruned transactions can not be expanded and verified because they are missing RCT data
VER_ASSERT(!tx.pruned, "Pruned transaction will not pass verRctNonSemanticsSimple");
// Calculate prefix hash
const crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
// Expand mixring, tx inputs, tx key images, prefix hash message, etc into the RCT sig
const bool exp_res = Blockchain::expand_transaction_2(tx, tx_prefix_hash, mix_ring);
VER_ASSERT(exp_res, "Failed to expand rct signatures!");
const rct::rctSig& rv = tx.rct_signatures;
// Check that expanded RCT mixring == input mixring
VER_ASSERT(rv.mixRing == mix_ring, "Failed to check ringct signatures: mismatched pubkeys/mixRing");
// Check CLSAG/MLSAG size against transaction input
const size_t n_sigs = rct::is_rct_clsag(rv.type) ? rv.p.CLSAGs.size() : rv.p.MGs.size();
VER_ASSERT(n_sigs == tx.vin.size(), "Failed to check ringct signatures: mismatched input sigs/vin sizes");
// For each input, check that the key images were copied into the expanded RCT sig correctly
for (size_t n = 0; n < n_sigs; ++n)
{
const crypto::key_image& nth_vin_image = boost::get<txin_to_key>(tx.vin[n]).k_image;
if (rct::is_rct_clsag(rv.type))
{
const bool ki_match = 0 == memcmp(&nth_vin_image, &rv.p.CLSAGs[n].I, 32);
VER_ASSERT(ki_match, "Failed to check ringct signatures: mismatched CLSAG key image");
}
else
{
const bool mg_nonempty = !rv.p.MGs[n].II.empty();
VER_ASSERT(mg_nonempty, "Failed to check ringct signatures: missing MLSAG key image");
const bool ki_match = 0 == memcmp(&nth_vin_image, &rv.p.MGs[n].II[0], 32);
VER_ASSERT(ki_match, "Failed to check ringct signatures: mismatched MLSAG key image");
}
}
// Mix ring data is now known to be correctly incorporated into the RCT sig inside tx.
return rct::verRctNonSemanticsSimple(rv);
}
// Create a unique identifier for pair of tx blob + mix ring
static crypto::hash calc_tx_mixring_hash(const transaction& tx, const rct::ctkeyM& mix_ring)
{
std::stringstream ss;
// Start with domain seperation
ss << config::HASH_KEY_TXHASH_AND_MIXRING;
// Then add TX hash
const crypto::hash tx_hash = get_transaction_hash(tx);
ss.write(tx_hash.data, sizeof(crypto::hash));
// Then serialize mix ring
binary_archive<true> ar(ss);
::do_serialize(ar, const_cast<rct::ctkeyM&>(mix_ring));
// Calculate hash of TX hash and mix ring blob
crypto::hash tx_and_mixring_hash;
get_blob_hash(ss.str(), tx_and_mixring_hash);
return tx_and_mixring_hash;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace cryptonote
{
bool ver_rct_non_semantics_simple_cached
(
transaction& tx,
const rct::ctkeyM& mix_ring,
rct_ver_cache_t& cache,
const std::uint8_t rct_type_to_cache
)
{
// Hello future Monero dev! If you got this assert, read the following carefully:
//
// For this version of RCT, the way we guaranteed that verification caches do not generate false
// positives (and thus possibly enabling double spends) is we take a hash of two things. One,
// we use get_transaction_hash() which gives us a (cryptographically secure) unique
// representation of all "knobs" controlled by the possibly malicious constructor of the
// transaction. Two, we take a hash of all *previously validated* blockchain data referenced by
// this transaction which is required to validate the ring signature. In our case, this is the
// 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;
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
// This cache only makes sense when it caches data from mempool first,
// so only "current fork version-enabled" RCT types need to be cached
if (tx.rct_signatures.type != rct_type_to_cache)
{
MDEBUG("RCT cache: tx " << get_transaction_hash(tx) << " skipped");
return expand_tx_and_ver_rct_non_sem(tx, mix_ring);
}
// Generate unique hash for tx+mix_ring pair
const crypto::hash tx_mixring_hash = calc_tx_mixring_hash(tx, mix_ring);
// Search cache for successful verification of same TX + mix ring combination
if (cache.has(tx_mixring_hash))
{
MDEBUG("RCT cache: tx " << get_transaction_hash(tx) << " hit");
return true;
}
// We had a cache miss, so now we must expand the mix ring and do full verification
MDEBUG("RCT cache: tx " << get_transaction_hash(tx) << " missed");
if (!expand_tx_and_ver_rct_non_sem(tx, mix_ring))
{
return false;
}
// At this point, the TX RCT verified successfully, so add it to the cache and return true
cache.add(tx_mixring_hash);
return true;
}
} // namespace cryptonote
@@ -0,0 +1,78 @@
// Copyright (c) 2023, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#pragma once
#include "common/data_cache.h"
#include "cryptonote_basic/cryptonote_basic.h"
namespace cryptonote
{
// Modifying this value should not affect consensus. You can adjust it for performance needs
static constexpr const size_t RCT_VER_CACHE_SIZE = 8192;
using rct_ver_cache_t = ::tools::data_cache<::crypto::hash, RCT_VER_CACHE_SIZE>;
/**
* @brief Cached version of rct::verRctNonSemanticsSimple
*
* This function will not affect how the transaction is serialized and it will never modify the
* transaction prefix.
*
* The reference to tx is mutable since the transaction's ring signatures may be expanded by
* Blockchain::expand_transaction_2. However, on cache hits, the transaction will not be
* expanded. This means that the caller does not need to call expand_transaction_2 on this
* transaction before passing it; the transaction will not successfully verify with "old" RCT data
* if the transaction has been otherwise modified since the last verification.
*
* But, if cryptonote::get_transaction_hash(tx) returns a "stale" hash, this function is not
* guaranteed to work. So make sure that the cryptonote::transaction passed has not had
* modifications to it since the last time its hash was fetched without properly invalidating the
* hashes.
*
* rct_type_to_cache can be any RCT version value as long as rct::verRctNonSemanticsSimple works for
* this RCT version, but for most applications, it doesn't make sense to not make this version
* the "current" RCT version (i.e. the version that transactions in the mempool are).
*
* @param tx transaction which contains RCT signature to verify
* @param mix_ring mixring referenced by this tx. THIS DATA MUST BE PREVIOUSLY VALIDATED
* @param cache saves tx+mixring hashes used to cache calls
* @param rct_type_to_cache Only RCT sigs with version (e.g. RCTTypeBulletproofPlus) will be cached
* @return true when verRctNonSemanticsSimple() w/ expanded tx.rct_signatures would return true
* @return false when verRctNonSemanticsSimple() w/ expanded tx.rct_signatures would return false
*/
bool ver_rct_non_semantics_simple_cached
(
transaction& tx,
const rct::ctkeyM& mix_ring,
rct_ver_cache_t& cache,
std::uint8_t rct_type_to_cache
);
} // namespace cryptonote
@@ -1020,7 +1020,7 @@ namespace cryptonote
for (auto& tx : arg.txs)
{
tx_verification_context tvc{};
if (!m_core.handle_incoming_tx({tx, crypto::null_hash}, tvc, tx_relay, true))
if (!m_core.handle_incoming_tx({tx, crypto::null_hash}, tvc, tx_relay, true) && !tvc.m_no_drop_offense)
{
LOG_PRINT_CCONTEXT_L1("Tx verification failed, dropping connection");
drop_connection(context, false, false);
+4 -3
View File
@@ -542,6 +542,7 @@ namespace levin
i_core_events* core_;
std::vector<blobdata> txs_;
boost::uuids::uuid source_;
relay_method tx_relay;
//! \pre Called in `zone_->strand`
void operator()()
@@ -549,7 +550,7 @@ namespace levin
if (!zone_ || !core_ || txs_.empty())
return;
if (!zone_->fluffing)
if (!zone_->fluffing || tx_relay == relay_method::local)
{
core_->on_transactions_relayed(epee::to_span(txs_), relay_method::stem);
for (int tries = 2; 0 < tries; tries--)
@@ -589,7 +590,7 @@ namespace levin
change_channels(change_channels&&) = default;
change_channels(const change_channels& source)
: zone_(source.zone_), map_(source.map_.clone())
: zone_(source.zone_), map_(source.map_.clone()), fluffing_(source.fluffing_)
{}
//! \pre Called within `zone_->strand`.
@@ -871,7 +872,7 @@ namespace levin
{
// this will change a local/forward tx to stem or fluff ...
zone_->strand.dispatch(
dandelionpp_notify{zone_, core_, std::move(txs), source}
dandelionpp_notify{zone_, core_, std::move(txs), source, tx_relay}
);
break;
}
+1
View File
@@ -526,6 +526,7 @@ namespace hw {
{0x2c97, 0x0001, 0, 0xffa0},
{0x2c97, 0x0004, 0, 0xffa0},
{0x2c97, 0x0005, 0, 0xffa0},
{0x2c97, 0x0006, 0, 0xffa0},
};
bool device_ledger::connect(void) {
+7 -1
View File
@@ -38,7 +38,7 @@ namespace net
{
void get_network_address_host_and_port(const std::string& address, std::string& host, std::string& port)
{
// require ipv6 address format "[addr:addr:addr:...:addr]:port"
// If IPv6 address format with port "[addr:addr:addr:...:addr]:port"
if (address.find(']') != std::string::npos)
{
host = address.substr(1, address.rfind(']') - 1);
@@ -47,6 +47,12 @@ namespace net
port = address.substr(address.rfind(':') + 1);
}
}
// Else if IPv6 address format without port e.g. "addr:addr:addr:...:addr"
else if (std::count(address.begin(), address.end(), ':') >= 2)
{
host = address;
}
// Else IPv4, Tor, I2P address or hostname
else
{
host = address.substr(0, address.rfind(':'));
+10
View File
@@ -38,6 +38,16 @@
namespace net
{
/*!
* \brief Takes a valid address string (IP, Tor, I2P, or DNS name) and splits it into host and port
*
* The host of an IPv6 addresses in the format "[x:x:..:x]:port" will have the braces stripped.
* For example, when the address is "[ffff::2023]", host will be set to "ffff::2023".
*
* \param address The address string one wants to split
* \param[out] host The host part of the address string. Is always set.
* \param[out] port The port part of the address string. Is only set when address string contains a port.
*/
void get_network_address_host_and_port(const std::string& address, std::string& host, std::string& port);
/*!
+37 -25
View File
@@ -247,7 +247,23 @@ namespace nodetool
if (it == m_blocked_hosts.end())
{
m_blocked_hosts[host_str] = limit;
added = true;
// if the host was already blocked due to being in a blocked subnet, let it be silent
bool matches_blocked_subnet = false;
if (addr.get_type_id() == epee::net_utils::address_type::ipv4)
{
auto ipv4_address = addr.template as<epee::net_utils::ipv4_network_address>();
for (auto jt = m_blocked_subnets.begin(); jt != m_blocked_subnets.end(); ++jt)
{
if (jt->first.matches(ipv4_address))
{
matches_blocked_subnet = true;
break;
}
}
}
if (!matches_blocked_subnet)
added = true;
}
else if (it->second < limit || !add_only)
it->second = limit;
@@ -317,6 +333,7 @@ namespace nodetool
limit = std::numeric_limits<time_t>::max();
else
limit = now + seconds;
const bool added = m_blocked_subnets.find(subnet) == m_blocked_subnets.end();
m_blocked_subnets[subnet] = limit;
// drop any connection to that subnet. This should only have to look into
@@ -349,7 +366,10 @@ namespace nodetool
conns.clear();
}
MCLOG_CYAN(el::Level::Info, "global", "Subnet " << subnet.host_str() << " blocked.");
if (added)
MCLOG_CYAN(el::Level::Info, "global", "Subnet " << subnet.host_str() << " blocked.");
else
MINFO("Subnet " << subnet.host_str() << " blocked.");
return true;
}
//-----------------------------------------------------------------------------------
@@ -645,20 +665,10 @@ namespace nodetool
{
using namespace boost::asio;
std::string host = addr;
// Split addr string into host string and port string
std::string host;
std::string port = std::to_string(default_port);
size_t colon_pos = addr.find_last_of(':');
size_t dot_pos = addr.find_last_of('.');
size_t square_brace_pos = addr.find('[');
// IPv6 will have colons regardless. IPv6 and IPv4 address:port will have a colon but also either a . or a [
// as IPv6 addresses specified as address:port are to be specified as "[addr:addr:...:addr]:port"
// One may also specify an IPv6 address as simply "[addr:addr:...:addr]" without the port; in that case
// the square braces will be stripped here.
if ((std::string::npos != colon_pos && std::string::npos != dot_pos) || std::string::npos != square_brace_pos)
{
net::get_network_address_host_and_port(addr, host, port);
}
net::get_network_address_host_and_port(addr, host, port);
MINFO("Resolving node address: host=" << host << ", port=" << port);
io_service io_srv;
@@ -695,34 +705,32 @@ namespace nodetool
std::set<std::string> full_addrs;
if (m_nettype == cryptonote::TESTNET)
{
full_addrs.insert("212.83.175.67:28080");
full_addrs.insert("212.83.172.165:28080");
full_addrs.insert("176.9.0.187:28080");
full_addrs.insert("88.99.173.38:28080");
full_addrs.insert("51.79.173.165:28080");
full_addrs.insert("192.99.8.110:28080");
full_addrs.insert("37.187.74.171:28080");
}
else if (m_nettype == cryptonote::STAGENET)
{
full_addrs.insert("162.210.173.150:38080");
full_addrs.insert("176.9.0.187:38080");
full_addrs.insert("88.99.173.38:38080");
full_addrs.insert("51.79.173.165:38080");
full_addrs.insert("192.99.8.110:38080");
full_addrs.insert("37.187.74.171:38080");
}
else if (m_nettype == cryptonote::FAKECHAIN)
{
}
else
{
full_addrs.insert("212.83.175.67:18080");
full_addrs.insert("212.83.172.165:18080");
full_addrs.insert("176.9.0.187:18080");
full_addrs.insert("88.198.163.90:18080");
full_addrs.insert("95.217.25.101:18080");
full_addrs.insert("136.244.105.131:18080");
full_addrs.insert("104.238.221.81:18080");
full_addrs.insert("66.85.74.134:18080");
full_addrs.insert("88.99.173.38:18080");
full_addrs.insert("51.79.173.165:18080");
full_addrs.insert("192.99.8.110:18080");
full_addrs.insert("37.187.74.171:18080");
}
return full_addrs;
}
@@ -857,6 +865,8 @@ namespace nodetool
"4pixvbejrvihnkxmduo2agsnmc3rrulrqc7s3cbwwrep6h6hrzsibeqd.onion:18083",
"zbjkbsxc5munw3qusl7j2hpcmikhqocdf4pqhnhtpzw5nt5jrmofptid.onion:18083",
"qz43zul2x56jexzoqgkx2trzwcfnr6l3hbtfcfx54g4r3eahy3bssjyd.onion:18083",
"plowsof3t5hogddwabaeiyrno25efmzfxyro2vligremt7sxpsclfaid.onion:18083",
"plowsoffjexmxalw73tkjmf422gq6575fc7vicuu4javzn2ynnte6tyd.onion:18083",
};
}
return {};
@@ -865,7 +875,9 @@ namespace nodetool
{
return {
"s3l6ke4ed3df466khuebb4poienoingwof7oxtbo6j4n56sghe3a.b32.i2p:18080",
"sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080"
"sel36x6fibfzujwvt4hf5gxolz6kd3jpvbjqg6o3ud2xtionyl2q.b32.i2p:18080",
"uqj3aphckqtjsitz7kxx5flqpwjlq5ppr3chazfued7xucv3nheq.b32.i2p:18080",
"vdmnehdjkpkg57nthgnjfuaqgku673r5bpbqg56ix6fyqoywgqrq.b32.i2p:18080",
};
}
return {};
@@ -2413,7 +2425,7 @@ namespace nodetool
return false;
}
return true;
});
}, "0.0.0.0", m_ssl_support);
if(!r)
{
LOG_WARNING_CC(context, "Failed to call connect_async, network error.");
+8
View File
@@ -97,6 +97,14 @@ namespace rct {
struct ctkey {
key dest;
key mask; //C here if public
bool operator==(const ctkey &other) const {
return (dest == other.dest) && (mask == other.mask);
}
bool operator!=(const ctkey &other) const {
return !(*this == other);
}
};
typedef std::vector<ctkey> ctkeyV;
typedef std::vector<ctkeyV> ctkeyM;
+2
View File
@@ -1275,6 +1275,8 @@ namespace cryptonote
add_reason(reason, "fee too low");
if ((res.too_few_outputs = tvc.m_too_few_outputs))
add_reason(reason, "too few outputs");
if ((res.tx_extra_too_big = tvc.m_tx_extra_too_big))
add_reason(reason, "tx-extra too big");
const std::string punctuation = reason.empty() ? "" : ": ";
if (tvc.m_verifivation_failed)
{
+3 -1
View File
@@ -88,7 +88,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 3
#define CORE_RPC_VERSION_MINOR 11
#define CORE_RPC_VERSION_MINOR 12
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -592,6 +592,7 @@ namespace cryptonote
bool fee_too_low;
bool too_few_outputs;
bool sanity_check_failed;
bool tx_extra_too_big;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_PARENT(rpc_access_response_base)
@@ -606,6 +607,7 @@ namespace cryptonote
KV_SERIALIZE(fee_too_low)
KV_SERIALIZE(too_few_outputs)
KV_SERIALIZE(sanity_check_failed)
KV_SERIALIZE(tx_extra_too_big)
END_KV_SERIALIZE_MAP()
};
typedef epee::misc_utils::struct_init<response_t> response;
+1 -3
View File
@@ -236,10 +236,8 @@ namespace cryptonote
*(uint32_t*)(hashing_blob.data() + 39) = SWAP32LE(nonce);
if (block.major_version >= RX_BLOCK_VERSION)
{
const uint64_t seed_height = is_current ? info.seed_height : info.previous_seed_height;
const crypto::hash &seed_hash = is_current ? info.seed_hash : info.previous_seed_hash;
const uint64_t height = cryptonote::get_block_height(block);
crypto::rx_slow_hash(height, seed_height, seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash.data, 0, 0);
crypto::rx_slow_hash(seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash.data);
}
else
{
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.18.1.2"
#define DEF_MONERO_VERSION "0.18.2.2"
#define DEF_MONERO_RELEASE_NAME "Fluorine Fermi"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@
+3 -3
View File
@@ -535,7 +535,7 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas
view_wallet->generate(path, password, address, viewkey);
// Export/Import outputs
auto outputs = m_wallet->export_outputs();
auto outputs = m_wallet->export_outputs(true/*all*/);
view_wallet->import_outputs(outputs);
// Copy scanned blockchain
@@ -553,7 +553,7 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas
// Export/Import key images
// We already know the spent status from the outputs we exported, thus no need to check them again
auto key_images = m_wallet->export_key_images();
auto key_images = m_wallet->export_key_images(true/*all*/);
uint64_t spent = 0;
uint64_t unspent = 0;
view_wallet->import_key_images(key_images.second, key_images.first, spent, unspent, false);
@@ -1782,7 +1782,7 @@ uint64_t WalletImpl::estimateTransactionFee(const std::vector<std::pair<std::str
m_wallet->use_fork_rules(HF_VERSION_CLSAG, 0),
m_wallet->use_fork_rules(HF_VERSION_BULLETPROOF_PLUS, 0),
m_wallet->use_fork_rules(HF_VERSION_VIEW_TAGS, 0),
m_wallet->get_base_fee(),
m_wallet->get_base_fee(priority),
m_wallet->get_fee_quantization_mask());
}
+5 -9
View File
@@ -1005,7 +1005,7 @@ gamma_picker::gamma_picker(const std::vector<uint64_t> &rct_offsets, double shap
const size_t blocks_to_consider = std::min<size_t>(rct_offsets.size(), blocks_in_a_year);
const size_t outputs_to_consider = rct_offsets.back() - (blocks_to_consider < rct_offsets.size() ? rct_offsets[rct_offsets.size() - blocks_to_consider - 1] : 0);
begin = rct_offsets.data();
end = rct_offsets.data() + rct_offsets.size() - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
end = rct_offsets.data() + rct_offsets.size() - (std::max(1, CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE) - 1);
num_rct_outputs = *(end - 1);
THROW_WALLET_EXCEPTION_IF(num_rct_outputs == 0, error::wallet_internal_error, "No rct outputs");
average_output_time = DIFFICULTY_TARGET_V2 * blocks_to_consider / static_cast<double>(outputs_to_consider); // this assumes constant target over the whole rct range
@@ -8408,7 +8408,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
else
{
// the base offset of the first rct output in the first unlocked block (or the one to be if there's none)
num_outs = rct_offsets[rct_offsets.size() - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE];
num_outs = gamma->get_num_rct_outs();
LOG_PRINT_L1("" << num_outs << " unlocked rct outputs");
THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error,
"histogram reports no unlocked rct outputs, not even ours");
@@ -8692,7 +8692,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
}
bool use_histogram = amount != 0;
if (!use_histogram)
num_outs = rct_offsets[rct_offsets.size() - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE];
num_outs = gamma->get_num_rct_outs();
// make sure the real outputs we asked for are really included, along
// with the correct key and mask: this guards against an active attack
@@ -13326,9 +13326,7 @@ size_t wallet2::import_outputs(const std::tuple<uint64_t, uint64_t, std::vector<
THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error,
"Imported outputs omit more outputs that we know of");
THROW_WALLET_EXCEPTION_IF(offset >= num_outputs, error::wallet_internal_error,
"Offset is larger than total outputs");
THROW_WALLET_EXCEPTION_IF(output_array.size() > num_outputs - offset, error::wallet_internal_error,
THROW_WALLET_EXCEPTION_IF(offset + output_array.size() > num_outputs, error::wallet_internal_error,
"Offset is larger than total outputs");
const size_t original_size = m_transfers.size();
@@ -13408,9 +13406,7 @@ size_t wallet2::import_outputs(const std::tuple<uint64_t, uint64_t, std::vector<
THROW_WALLET_EXCEPTION_IF(offset > m_transfers.size(), error::wallet_internal_error,
"Imported outputs omit more outputs that we know of. Try using export_outputs all.");
THROW_WALLET_EXCEPTION_IF(offset >= num_outputs, error::wallet_internal_error,
"Offset is larger than total outputs");
THROW_WALLET_EXCEPTION_IF(output_array.size() > num_outputs - offset, error::wallet_internal_error,
THROW_WALLET_EXCEPTION_IF(offset + output_array.size() > num_outputs, error::wallet_internal_error,
"Offset is larger than total outputs");
const size_t original_size = m_transfers.size();
+1
View File
@@ -101,6 +101,7 @@ namespace tools
uint64_t pick();
gamma_picker(const std::vector<uint64_t> &rct_offsets);
gamma_picker(const std::vector<uint64_t> &rct_offsets, double shape, double scale);
uint64_t get_num_rct_outs() const { return num_rct_outputs; }
private:
struct gamma_engine
+1 -2
View File
@@ -155,8 +155,7 @@ bool wallet2::search_for_rpc_payment(uint64_t credits_target, uint32_t n_threads
const uint8_t major_version = hashing_blob[0];
if (major_version >= RX_BLOCK_VERSION)
{
const int miners = 1;
crypto::rx_slow_hash(height, seed_height, seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash[i].data, miners, 0);
crypto::rx_slow_hash(seed_hash.data, hashing_blob.data(), hashing_blob.size(), hash[i].data);
}
else
{
Binary file not shown.
+1
View File
@@ -91,6 +91,7 @@ set(unit_tests_sources
unbound.cpp
uri.cpp
varint.cpp
ver_rct_non_semantics_simple_cached.cpp
ringct.cpp
output_selection.cpp
vercmp.cpp
+11
View File
@@ -158,6 +158,17 @@ TEST(DNSResolver, GetTXTRecord)
EXPECT_STREQ("donate.getmonero.org", addr.c_str());
}
TEST(DNSResolver, Localhost)
{
tools::DNSResolver resolver = tools::DNSResolver::create();
bool avail, valid;
std::vector<std::string> ips = resolver.get_ipv4("localhost", avail, valid);
ASSERT_EQ(1, ips.size());
ASSERT_EQ("127.0.0.1", ips[0]);
}
bool is_equal(const char *s, const std::vector<std::string> &v) { return v.size() == 1 && v[0] == s; }
TEST(DNS_PUBLIC, empty) { EXPECT_TRUE(tools::dns_utils::parse_dns_public("").empty()); }
+84 -15
View File
@@ -792,25 +792,33 @@ TEST_F(levin_notify, local_without_padding)
notifier.new_out_connection();
io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'f');
txs[1].resize(200, 'e');
std::vector<cryptonote::blobdata> my_txs(2);
my_txs[0].resize(100, 'f');
my_txs[1].resize(200, 'e');
std::vector<cryptonote::blobdata> sorted_txs = txs;
std::sort(sorted_txs.begin(), sorted_txs.end());
std::vector<cryptonote::blobdata> their_txs{2};
their_txs[0].resize(300, 'g');
their_txs[1].resize(250, 'h');
std::vector<cryptonote::blobdata> my_sorted_txs = my_txs;
std::sort(my_sorted_txs.begin(), my_sorted_txs.end());
std::vector<cryptonote::blobdata> their_sorted_txs = their_txs;
std::sort(their_sorted_txs.begin(), their_sorted_txs.end());
ASSERT_EQ(10u, contexts_.size());
bool has_stemmed = false;
bool has_fluffed = false;
while (!has_stemmed || !has_fluffed)
{
// run their "their" txes first
auto context = contexts_.begin();
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local));
EXPECT_TRUE(notifier.send_txs(their_txs, context->get_id(), cryptonote::relay_method::stem));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
const bool is_stem = events_.has_stem_txes();
EXPECT_EQ(txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
EXPECT_EQ(their_txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
if (!is_stem)
{
@@ -836,13 +844,41 @@ TEST_F(levin_notify, local_without_padding)
{
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
if (is_stem)
EXPECT_EQ(txs, notification.txs);
EXPECT_EQ(their_txs, notification.txs);
else
EXPECT_EQ(sorted_txs, notification.txs);
EXPECT_EQ(their_sorted_txs, notification.txs);
EXPECT_TRUE(notification._.empty());
EXPECT_EQ(!is_stem, notification.dandelionpp_fluff);
}
// run "my" txes which must always be stem
context = contexts_.begin();
EXPECT_TRUE(notifier.send_txs(my_txs, context->get_id(), cryptonote::relay_method::local));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
EXPECT_TRUE(events_.has_stem_txes());
EXPECT_EQ(my_txs, events_.take_relayed(cryptonote::relay_method::stem));
send_count = 0;
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
{
const std::size_t sent = context->process_send_queue();
if (sent)
{
EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
}
send_count += sent;
}
EXPECT_EQ(1u, send_count);
EXPECT_EQ(1u, receiver_.notified_size());
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(my_txs, notification.txs);
EXPECT_TRUE(notification._.empty());
EXPECT_TRUE(!notification.dandelionpp_fluff);
has_stemmed |= is_stem;
has_fluffed |= !is_stem;
notifier.run_epoch();
@@ -1170,22 +1206,27 @@ TEST_F(levin_notify, local_with_padding)
notifier.new_out_connection();
io_service_.poll();
std::vector<cryptonote::blobdata> txs(2);
txs[0].resize(100, 'e');
txs[1].resize(200, 'f');
std::vector<cryptonote::blobdata> my_txs(2);
my_txs[0].resize(100, 'e');
my_txs[1].resize(200, 'f');
std::vector<cryptonote::blobdata> their_txs{2};
their_txs[0].resize(300, 'g');
their_txs[1].resize(250, 'h');
ASSERT_EQ(10u, contexts_.size());
bool has_stemmed = false;
bool has_fluffed = false;
while (!has_stemmed || !has_fluffed)
{
// run their "their" txes first
auto context = contexts_.begin();
EXPECT_TRUE(notifier.send_txs(txs, context->get_id(), cryptonote::relay_method::local));
EXPECT_TRUE(notifier.send_txs(their_txs, context->get_id(), cryptonote::relay_method::stem));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
const bool is_stem = events_.has_stem_txes();
EXPECT_EQ(txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
EXPECT_EQ(their_txs, events_.take_relayed(is_stem ? cryptonote::relay_method::stem : cryptonote::relay_method::fluff));
if (!is_stem)
{
@@ -1211,11 +1252,39 @@ TEST_F(levin_notify, local_with_padding)
for (unsigned count = 0; count < (is_stem ? 1u : 9u); ++count)
{
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(txs, notification.txs);
EXPECT_EQ(their_txs, notification.txs);
EXPECT_FALSE(notification._.empty());
EXPECT_EQ(!is_stem, notification.dandelionpp_fluff);
}
// run "my" txes which must always be stem
context = contexts_.begin();
EXPECT_TRUE(notifier.send_txs(my_txs, context->get_id(), cryptonote::relay_method::local));
io_service_.reset();
ASSERT_LT(0u, io_service_.poll());
EXPECT_TRUE(events_.has_stem_txes());
EXPECT_EQ(my_txs, events_.take_relayed(cryptonote::relay_method::stem));
send_count = 0;
EXPECT_EQ(0u, context->process_send_queue());
for (++context; context != contexts_.end(); ++context)
{
const std::size_t sent = context->process_send_queue();
if (sent)
{
EXPECT_EQ(1u, (context - contexts_.begin()) % 2);
}
send_count += sent;
}
EXPECT_EQ(1u, send_count);
EXPECT_EQ(1u, receiver_.notified_size());
auto notification = receiver_.get_notification<cryptonote::NOTIFY_NEW_TRANSACTIONS>().second;
EXPECT_EQ(my_txs, notification.txs);
EXPECT_FALSE(notification._.empty());
EXPECT_TRUE(!notification.dandelionpp_fluff);
has_stemmed |= is_stem;
has_fluffed |= !is_stem;
notifier.run_epoch();
+35
View File
@@ -936,6 +936,41 @@ TEST(get_network_address, ipv4subnet)
EXPECT_STREQ("12.34.0.0/16", address->str().c_str());
}
namespace
{
void na_host_and_port_test(std::string addr, std::string exp_host, std::string exp_port)
{
std::string host{"xxxxx"};
std::string port{"xxxxx"};
net::get_network_address_host_and_port(addr, host, port);
EXPECT_EQ(exp_host, host);
EXPECT_EQ(exp_port, port);
}
} // anonymous namespace
TEST(get_network_address_host_and_port, ipv4)
{
na_host_and_port_test("9.9.9.9", "9.9.9.9", "xxxxx");
na_host_and_port_test("9.9.9.9:18081", "9.9.9.9", "18081");
}
TEST(get_network_address_host_and_port, ipv6)
{
na_host_and_port_test("::ffff", "::ffff", "xxxxx");
na_host_and_port_test("[::ffff]", "::ffff", "xxxxx");
na_host_and_port_test("[::ffff]:00231", "::ffff", "00231");
na_host_and_port_test("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", "xxxxx");
na_host_and_port_test("[7777:7777:7777:7777:7777:7777:7777:7777]", "7777:7777:7777:7777:7777:7777:7777:7777", "xxxxx");
na_host_and_port_test("[7777:7777:7777:7777:7777:7777:7777:7777]:48080", "7777:7777:7777:7777:7777:7777:7777:7777", "48080");
}
TEST(get_network_address_host_and_port, hostname)
{
na_host_and_port_test("localhost", "localhost", "xxxxx");
na_host_and_port_test("bar:29080", "bar", "29080"); // Issue https://github.com/monero-project/monero/issues/8633
na_host_and_port_test("xmrchain.net:18081", "xmrchain.net", "18081");
}
namespace
{
using stream_type = boost::asio::ip::tcp;
@@ -0,0 +1,426 @@
// Copyright (c) 2023, 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 <sstream>
#define IN_UNIT_TESTS // To access Blockchain::{expand_transaction_2, verRctNonSemanticsSimpleCached}
#include "gtest/gtest.h"
#include "unit_tests_utils.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "cryptonote_core/blockchain.h"
#include "file_io_utils.h"
#include "misc_log_ex.h"
#include "ringct/rctSigs.h"
namespace cryptonote
{
// declaration not provided in cryptonote_format_utils.h, but definition is not static ;)
bool expand_transaction_1(transaction &tx, bool base_only);
}
namespace
{
/**
* @brief Make rct::ctkey from hex string representation of destionation and mask
*
* @param dest_hex
* @param mask_hex
* @return rct::ctkey
*/
static rct::ctkey make_ctkey(const char* dest_hex, const char* mask_hex)
{
rct::key dest;
rct::key mask;
CHECK_AND_ASSERT_THROW_MES(epee::from_hex::to_buffer(epee::as_mut_byte_span(dest), dest_hex), "dest bad hex: " << dest_hex);
CHECK_AND_ASSERT_THROW_MES(epee::from_hex::to_buffer(epee::as_mut_byte_span(mask), mask_hex), "mask bad hex: " << mask_hex);
return {dest, mask};
}
template <typename T>
static std::string stringify_with_do_serialize(const T& t)
{
std::stringstream ss;
binary_archive<true> ar(ss);
CHECK_AND_ASSERT_THROW_MES(ar.good(), "Archiver is not in a good state. This shouldn't happen!");
::do_serialize(ar, const_cast<T&>(t));
return ss.str();
}
static bool check_tx_is_expanded(const cryptonote::transaction& tx, const rct::ctkeyM& pubkeys)
{
// Ripped from cryptonote_core/blockchain.cpp
const rct::rctSig& rv = tx.rct_signatures;
if (pubkeys.size() != rv.mixRing.size())
{
MERROR("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
return false;
}
for (size_t i = 0; i < pubkeys.size(); ++i)
{
if (pubkeys[i].size() != rv.mixRing[i].size())
{
MERROR("Failed to check ringct signatures: mismatched pubkeys/mixRing size");
return false;
}
}
for (size_t n = 0; n < pubkeys.size(); ++n)
{
for (size_t m = 0; m < pubkeys[n].size(); ++m)
{
if (pubkeys[n][m].dest != rct::rct2pk(rv.mixRing[n][m].dest))
{
MERROR("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m);
return false;
}
if (pubkeys[n][m].mask != rct::rct2pk(rv.mixRing[n][m].mask))
{
MERROR("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m);
return false;
}
}
}
const size_t n_sigs = rct::is_rct_clsag(rv.type) ? rv.p.CLSAGs.size() : rv.p.MGs.size();
if (n_sigs != tx.vin.size())
{
MERROR("Failed to check ringct signatures: mismatched MGs/vin sizes");
return false;
}
for (size_t n = 0; n < tx.vin.size(); ++n)
{
bool error;
if (rct::is_rct_clsag(rv.type))
error = memcmp(&boost::get<cryptonote::txin_to_key>(tx.vin[n]).k_image, &rv.p.CLSAGs[n].I, 32);
else
error = rv.p.MGs[n].II.empty() || memcmp(&boost::get<cryptonote::txin_to_key>(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32);
if (error)
{
MERROR("Failed to check ringct signatures: mismatched key image");
return false;
}
}
return true;
}
/**
* @brief Perform expand_transaction_1 and Blockchain::expand_transaction_2 on a certain transaction
*/
static void expand_transaction_fully(cryptonote::transaction& tx, const rct::ctkeyM& input_pubkeys)
{
const crypto::hash tx_prefix_hash = cryptonote::get_transaction_prefix_hash(tx);
CHECK_AND_ASSERT_THROW_MES(cryptonote::expand_transaction_1(tx, false), "expand 1 failed");
CHECK_AND_ASSERT_THROW_MES
(
cryptonote::Blockchain::expand_transaction_2(tx, tx_prefix_hash, input_pubkeys),
"expand 2 failed"
);
CHECK_AND_ASSERT_THROW_MES(!memcmp(&tx_prefix_hash, &tx.rct_signatures.message, 32), "message check failed");
CHECK_AND_ASSERT_THROW_MES(input_pubkeys == tx.rct_signatures.mixRing, "mixring check failed");
CHECK_AND_ASSERT_THROW_MES(check_tx_is_expanded(tx, input_pubkeys), "tx expansion check 2 failed");
}
/**
* @brief Mostly construct transaction from binary file and provided mix ring pubkeys
*
* Most important to us, this should populate the .rct_signatures.message and
* .rct_signatures.mixRings fields of the transaction.
*
* @param file_name relative file path in unit test data directory
* @param input_pubkeys manually retrived input pubkey destination / masks for each ring
* @return cryptonote::transaction the expanded transaction
*/
static cryptonote::transaction expand_transaction_from_bin_file_and_pubkeys
(
const char* file_name,
const rct::ctkeyM& input_pubkeys
)
{
cryptonote::transaction transaction;
const boost::filesystem::path tx_json_path = unit_test::data_dir / file_name;
std::string tx_blob;
CHECK_AND_ASSERT_THROW_MES
(
epee::file_io_utils::load_file_to_string(tx_json_path.string(), tx_blob),
"loading file to string failed"
);
CHECK_AND_ASSERT_THROW_MES
(
cryptonote::parse_and_validate_tx_from_blob(tx_blob, transaction),
"TX blob could not be parsed"
);
expand_transaction_fully(transaction, input_pubkeys);
return transaction;
}
/**
* @brief Return whether a modification changes blob resulting from do_serialize()
*/
template <typename T, class TModifier>
static bool modification_changes_do_serialize
(
const T& og_obj,
TModifier& obj_modifier_func,
bool expected_change
)
{
T modded_obj = og_obj;
obj_modifier_func(modded_obj);
const std::string og_blob = stringify_with_do_serialize(og_obj);
const std::string modded_blob = stringify_with_do_serialize(modded_obj);
const bool did_change = modded_blob != og_blob;
if (did_change != expected_change)
{
const std::string og_hex = epee::to_hex::string(epee::strspan<uint8_t>(og_blob));
const std::string modded_hex = epee::to_hex::string(epee::strspan<uint8_t>(modded_blob));
MERROR("unexpected: modded_blob '" << modded_hex << "' vs og_blob ' << " << og_hex << "'");
}
return did_change;
}
// Contains binary representation of mainnet transaction (height 2777777):
// e89415b95564aa7e3587c91422756ba5303e727996e19c677630309a0d52a7ca
static constexpr const char* tx1_file_name = "txs/bpp_tx_e89415.bin";
// This contains destination key / mask pairs for each output in the input ring of the above tx
static const rct::ctkeyM tx1_input_pubkeys =
{{
make_ctkey("e50f476129d40af31e0938743f7f2d60e867aab31294f7acaf6e38f0976f0228", "51e788ddf5c95c124a7314d45a91b52d60db25a0572de9c2b4ec515aca3d4481"),
make_ctkey("804245d067fcfe6cd66376db0571869989bc68b3e22a0f902109c7530df47a59", "c3cc65d3b3a05defaa05213dc3b0496f9b86dbeeefbff28db34b134b6ee3230b"),
make_ctkey("527563a03b498e47732b815f5f0c5875a70e0fb71a37c88123f0f8686349fae4", "04417c03b397cd11e403275ec89cb0ab5b8476bb88470e9ae7208ea63dacf073"),
make_ctkey("bffca8b5c7fe4235ba7136d6b5325f63df343dc147940b677f50217f8953bca6", "5cd8c5e54e07275422c9c5a9f4a7268d26c494ffba419e878b7e873a02ae2e76"),
make_ctkey("1f73385ea74308aa78b5abf585faac14a5e78a6e23f0f68c9c14681108b28ef0", "5c02b3156daaa8ec476d3244439d90efa266f3e51cb9c8eb384d8b9a8efaa024"),
make_ctkey("a2421eae8bb256644b34feeab48c6086c2c9feb40d2643436dc45e303eee8ab2", "787823abffa988b56d4a7b4a834630f71520220fd82fad035955e616ec095788"),
make_ctkey("17d8d8dc1e1c25b7295f2eab44c4ccc08a629b8e8d781bbb6f9a51a9561bcd4c", "db1ea24be6947e03176a297160dba16d65f37751bb0ef2ba71a4590d12b61dfc"),
make_ctkey("2c39348a9ab04dbabe3b5249819b7845ed8aaebd0d8eddd98bda0bf40753a398", "4e6cd25fbd10e2e040be84e3bf8043c612daeef625e66a5e5bcff88c9c46e82c"),
make_ctkey("c4c97157f23b45c7084526aaa9958fe858bebe446a7efa22c491c439b74271b1", "e251db2c86193a11a5bffefffe48c20e3d92a8dc98cb3a2f41704e565bcd860a"),
make_ctkey("d342045525139a8551bcdfa7aa0117d2ac2327cb6cf449ca59420c300e4471a5", "789c11f72060ad80f4cda5d89b24d49f9435bf765598dea7a91776e99f05f87c"),
make_ctkey("9a972ccf2c74f648070b0be839749c98eca87166de401a6c1f59e64b938a46c1", "5444cbed5cec31fb6ed1612f815d292f2bf3d2ff584bbcd8e5201ec59670d414"),
make_ctkey("49ccb806ccf5cbd74bae8d9fb2da8918ab61d0774ee6a6c3a6ccd237db22a088", "0c5db942fb44f29f6ef956e24db91f98a6de6e7288b0b04d01b8f260453d1431"),
make_ctkey("74417e8d1483df2df6fe68c88fc9a72639c35d765b38351b838521addf45dadc", "a1a606d6c4762ef51c1759bcb8b5c88be1d323025400c41fe6885431064b64dc"),
make_ctkey("48c4c349adaf7b3be27656ea70d1c83b93e1511bb0aac987861a4da9689b0e95", "ad14ffd5edac199ea7c5437d558089b0f2f03aa74bde43611322d769968b5a1c"),
make_ctkey("2d2ffade0f85ddd83a036469e49542e93cad94f9bea535f0ea2eb2f56304517e", "bcc48d00bd06dc5439200e749d0caf8a062b072d0c0eb1f78f6a4d8f2373e5f4"),
make_ctkey("4ee857d0ce17f66eca9c81eb326e404ceb50c8198248f2f827c440ee7aa0c0d7", "a8a9d61d4abbfb123630ffd214c834cc45113eaa51dd2f904cc6ae0c3c5d70e3")
}};
} // anonymous namespace
TEST(verRctNonSemanticsSimple, tx1_preconditions)
{
// If this unit test fails, something changed about transaction deserialization / expansion or
// something changed about RingCT signature verification.
cryptonote::rct_ver_cache_t rct_ver_cache;
cryptonote::transaction tx = expand_transaction_from_bin_file_and_pubkeys
(tx1_file_name, tx1_input_pubkeys);
const rct::rctSig& rs = tx.rct_signatures;
const crypto::hash tx_prefix_hash = cryptonote::get_transaction_prefix_hash(tx);
EXPECT_EQ(1, tx.vin.size());
EXPECT_EQ(2, tx.vout.size());
const rct::key expected_sig_msg = rct::hash2rct(tx_prefix_hash);
EXPECT_EQ(expected_sig_msg, rs.message);
EXPECT_EQ(1, rs.mixRing.size());
EXPECT_EQ(16, rs.mixRing[0].size());
EXPECT_EQ(0, rs.pseudoOuts.size());
EXPECT_EQ(0, rs.p.rangeSigs.size());
EXPECT_EQ(0, rs.p.bulletproofs.size());
EXPECT_EQ(1, rs.p.bulletproofs_plus.size());
EXPECT_EQ(2, rs.p.bulletproofs_plus[0].V.size());
EXPECT_EQ(7, rs.p.bulletproofs_plus[0].L.size());
EXPECT_EQ(7, rs.p.bulletproofs_plus[0].R.size());
EXPECT_EQ(0, rs.p.MGs.size());
EXPECT_EQ(1, rs.p.CLSAGs.size());
EXPECT_EQ(16, rs.p.CLSAGs[0].s.size());
EXPECT_EQ(1, rs.p.pseudoOuts.size());
EXPECT_EQ(tx1_input_pubkeys, rs.mixRing);
EXPECT_EQ(2, rs.outPk.size());
EXPECT_TRUE(rct::verRctSemanticsSimple(rs));
EXPECT_TRUE(rct::verRctNonSemanticsSimple(rs));
EXPECT_TRUE(rct::verRctSimple(rs));
EXPECT_TRUE(cryptonote::ver_rct_non_semantics_simple_cached(tx, tx1_input_pubkeys, rct_ver_cache, rct::RCTTypeBulletproofPlus));
EXPECT_TRUE(cryptonote::ver_rct_non_semantics_simple_cached(tx, tx1_input_pubkeys, rct_ver_cache, rct::RCTTypeBulletproofPlus));
}
#define SERIALIZABLE_SIG_CHANGES_SUBTEST(fieldmodifyclause) \
do { \
const auto sig_modifier_func = [](rct::rctSig& rs) { rs.fieldmodifyclause; }; \
EXPECT_TRUE(modification_changes_do_serialize(original_sig, sig_modifier_func, true)); \
} while (0); \
TEST(verRctNonSemanticsSimple, serializable_sig_changes)
{
// Hello, future visitors. If this unit test fails, then fields of rctSig have been dropped from
// serialization.
const cryptonote::transaction tx = expand_transaction_from_bin_file_and_pubkeys
(tx1_file_name, tx1_input_pubkeys);
const rct::rctSig& original_sig = tx.rct_signatures;
// These are the subtests most likely to fail. Fields 'message' and 'mixRing' are not serialized
// when sent over the wire, since they can be reconstructed from transaction data. However, they
// are serialized by ::do_serialize(rctSig).
// How signatures are serialized for the blockchain can be found in the methods
// rct::rctSigBase::serialize_rctsig_base and rct::rctSigPrunable::serialize_rctsig_prunable.
SERIALIZABLE_SIG_CHANGES_SUBTEST(message.bytes[31]++)
SERIALIZABLE_SIG_CHANGES_SUBTEST(mixRing.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(mixRing[0].push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(mixRing[0][8].dest[10]--)
SERIALIZABLE_SIG_CHANGES_SUBTEST(mixRing[0][15].mask[3]--)
// rctSigBase changes. These subtests are less likely to break
SERIALIZABLE_SIG_CHANGES_SUBTEST(type ^= 23)
SERIALIZABLE_SIG_CHANGES_SUBTEST(pseudoOuts.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(ecdhInfo.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(outPk.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(outPk[0].dest[14]--)
SERIALIZABLE_SIG_CHANGES_SUBTEST(outPk[1].dest[14]--)
SERIALIZABLE_SIG_CHANGES_SUBTEST(outPk[0].mask[14]--)
SERIALIZABLE_SIG_CHANGES_SUBTEST(outPk[1].mask[14]--)
SERIALIZABLE_SIG_CHANGES_SUBTEST(txnFee *= 2023)
// rctSigPrunable changes
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.rangeSigs.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].A[13] -= 7)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].A1[13] -= 7)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].B[13] -= 7)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].r1[13] -= 7)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].s1[13] -= 7)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].d1[13] -= 7)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].L.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].L[2][13] -= 7)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].R.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].R[2][13] -= 7)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.MGs.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.CLSAGs.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.CLSAGs[0].s.push_back({}))
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.CLSAGs[0].s[15][31] ^= 69)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.CLSAGs[0].c1[0] /= 3)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.CLSAGs[0].D[0] /= 3)
SERIALIZABLE_SIG_CHANGES_SUBTEST(p.pseudoOuts.push_back({}))
// Uncomment line below to sanity check SERIALIZABLE_SIG_CHANGES_SUBTEST
// SERIALIZABLE_SIG_CHANGES_SUBTEST(message) // should fail
}
#define UNSERIALIZABLE_SIG_CHANGES_SUBTEST(fieldmodifyclause) \
do { \
const auto sig_modifier_func = [](rct::rctSig& rs) { rs.fieldmodifyclause; }; \
EXPECT_FALSE(modification_changes_do_serialize(original_sig, sig_modifier_func, false)); \
} while (0); \
TEST(verRctNonSemanticsSimple, unserializable_sig_changes)
{
// Hello, future visitors. If this unit test fails, then congrats! ::do_serialize(rctSig) became
// better at uniquely representing rctSig.
const cryptonote::transaction tx = expand_transaction_from_bin_file_and_pubkeys
(tx1_file_name, tx1_input_pubkeys);
const rct::rctSig& original_sig = tx.rct_signatures;
UNSERIALIZABLE_SIG_CHANGES_SUBTEST(p.CLSAGs[0].I[14]++)
UNSERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].V.push_back({}))
UNSERIALIZABLE_SIG_CHANGES_SUBTEST(p.bulletproofs_plus[0].V[1][31]--)
// Uncomment line below to sanity check UNSERIALIZABLE_SIG_CHANGES_SUBTEST_SHORTCUT
// UNSERIALIZABLE_SIG_CHANGES_SUBTEST_SHORTCUT(message[2]++) // should fail
}
#define SERIALIZABLE_MIXRING_CHANGES_SUBTEST(fieldmodifyclause) \
do { \
using mr_mod_func_t = std::function<void(rct::ctkeyM&)>; \
const mr_mod_func_t mr_modifier_func = [&](rct::ctkeyM& mr) { mr fieldmodifyclause; }; \
EXPECT_TRUE(modification_changes_do_serialize(original_mixring, mr_modifier_func, true)); \
} while (0); \
TEST(verRctNonSemanticsSimple, serializable_mixring_changes)
{
// Hello, future Monero devs! If this unit test fails, a huge concensus-related assumption has
// been broken and verRctNonSemanticsSimpleCached needs to be reevalulated for validity. If it
// is not, there may be an exploit which allows for double-spending. See the implementation for
// more comments on the uniqueness of the internal cache hash.
const rct::ctkeyM original_mixring = tx1_input_pubkeys;
const size_t mlen = tx1_input_pubkeys.size();
ASSERT_EQ(1, mlen);
const size_t nlen = tx1_input_pubkeys[0].size();
ASSERT_EQ(16, nlen);
SERIALIZABLE_MIXRING_CHANGES_SUBTEST(.clear())
SERIALIZABLE_MIXRING_CHANGES_SUBTEST(.push_back({}))
SERIALIZABLE_MIXRING_CHANGES_SUBTEST([0].clear())
SERIALIZABLE_MIXRING_CHANGES_SUBTEST([0].push_back({}))
SERIALIZABLE_MIXRING_CHANGES_SUBTEST([0][0].dest[4]--)
SERIALIZABLE_MIXRING_CHANGES_SUBTEST([0][15].mask[31]--)
// Loop through all bytes of the mixRing and check for serialiable changes
for (size_t i = 0; i < mlen; ++i)
{
for (size_t j = 0; j < nlen; ++j)
{
static_assert(sizeof(rct::key) == 32, "rct::key size wrong");
for (size_t k = 0; k < sizeof(rct::key); ++k)
{
SERIALIZABLE_MIXRING_CHANGES_SUBTEST([i][j].dest[k]++)
SERIALIZABLE_MIXRING_CHANGES_SUBTEST([i][j].mask[k]++)
}
}
}
}
#define EXPAND_TRANSACTION_2_FAILURES_SUBTEST(fieldmodifyclause) \
do { \
cryptonote::transaction test_tx = original_tx; \
test_tx.fieldmodifyclause; \
test_tx.invalidate_hashes(); \
EXPECT_FALSE(check_tx_is_expanded(test_tx, original_mixring)); \
} while (0); \
TEST(verRctNonSemanticsSimple, expand_transaction_2_failures)
{
cryptonote::transaction original_tx = expand_transaction_from_bin_file_and_pubkeys
(tx1_file_name, tx1_input_pubkeys);
rct::ctkeyM original_mixring = tx1_input_pubkeys;
EXPAND_TRANSACTION_2_FAILURES_SUBTEST(rct_signatures.p.CLSAGs[0].I[0]++)
EXPAND_TRANSACTION_2_FAILURES_SUBTEST(rct_signatures.mixRing[0][15].dest[31]++)
EXPAND_TRANSACTION_2_FAILURES_SUBTEST(rct_signatures.mixRing[0][15].mask[31]++)
}