forked from such-gitea/wownero
Compare commits
48 Commits
v0.11
...
release-v0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e921c3b8a3 | ||
|
|
f626f0a412 | ||
|
|
d9c70f5a08 | ||
|
|
8d7701a67d | ||
|
|
2a8a05af56 | ||
|
|
bb88fdfcdd | ||
|
|
1a86d67ef4 | ||
|
|
2c26e205bd | ||
|
|
48b8b5287b | ||
|
|
a1fde20408 | ||
|
|
6824ad23f6 | ||
|
|
dee8d4a2e2 | ||
|
|
272ddf78bf | ||
|
|
becc181499 | ||
|
|
ef8637a396 | ||
|
|
085d0f1994 | ||
|
|
710430ea51 | ||
|
|
e292b49308 | ||
|
|
e815479531 | ||
|
|
b0ef1ce118 | ||
|
|
ed71a89138 | ||
|
|
90f8943da6 | ||
|
|
a2dc960250 | ||
|
|
a03e5c3905 | ||
|
|
e2d02caf67 | ||
|
|
a985911453 | ||
|
|
f1ca5b5fd1 | ||
|
|
eb2a7342b8 | ||
|
|
a21819cc22 | ||
|
|
3341cded57 | ||
|
|
4578688c7b | ||
|
|
62ae03bfd3 | ||
|
|
f8d0f857f6 | ||
|
|
e44d831d7f | ||
|
|
12ad6748a4 | ||
|
|
b1710a4fcc | ||
|
|
65764dce8c | ||
|
|
c8b4cdffdc | ||
|
|
a0e4d6b4c2 | ||
|
|
b878068e84 | ||
|
|
143ac20baf | ||
|
|
215fccb71c | ||
|
|
4f1fc36c9b | ||
|
|
0a6465ebcc | ||
|
|
6573d10b5b | ||
|
|
2482733bc7 | ||
|
|
f2b4a3be47 | ||
|
|
a8eb29dbe7 |
27
.github/workflows/build.yml
vendored
27
.github/workflows/build.yml
vendored
@@ -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
|
||||
@@ -79,10 +79,10 @@ jobs:
|
||||
matrix:
|
||||
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 }}
|
||||
@@ -105,10 +105,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: ~/.ccache
|
||||
key: ccache-${{ runner.os }}-libwallet-${{ github.sha }}
|
||||
@@ -133,11 +133,11 @@ jobs:
|
||||
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 }}
|
||||
@@ -167,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: |
|
||||
@@ -177,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 }}
|
||||
|
||||
11
.github/workflows/depends.yml
vendored
11
.github/workflows/depends.yml
vendored
@@ -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 }}
|
||||
|
||||
2
.github/workflows/gitian.yml
vendored
2
.github/workflows/gitian.yml
vendored
@@ -42,7 +42,7 @@ jobs:
|
||||
echo \`\`\` >> $GITHUB_STEP_SUMMARY
|
||||
shasum -a256 * >> $GITHUB_STEP_SUMMARY
|
||||
echo \`\`\` >> $GITHUB_STEP_SUMMARY
|
||||
- uses: actions/upload-artifact@v3.1.0
|
||||
- uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ matrix.operating-system.name }}
|
||||
path: |
|
||||
|
||||
@@ -413,7 +413,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
else()
|
||||
set(DEFAULT_BUILD_DEBUG_UTILITIES OFF)
|
||||
endif()
|
||||
option(BUILD_DEBUG_UTILITIES "Build debug utilities." DEFAULT_BUILD_DEBUG_UTILITIES)
|
||||
option(BUILD_DEBUG_UTILITIES "Build debug utilities." ${DEFAULT_BUILD_DEBUG_UTILITIES})
|
||||
|
||||
if(OSSFUZZ)
|
||||
message(STATUS "Using OSS-Fuzz fuzzing system")
|
||||
@@ -1117,7 +1117,8 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)")
|
||||
set(EXTRA_LIBRARIES socket nsl resolv)
|
||||
elseif(NOT MSVC AND NOT DEPENDS)
|
||||
find_library(RT rt)
|
||||
set(EXTRA_LIBRARIES ${RT})
|
||||
find_library(Z z)
|
||||
set(EXTRA_LIBRARIES ${RT} ${Z})
|
||||
endif()
|
||||
|
||||
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
|
||||
|
||||
@@ -96,7 +96,7 @@ Dates are provided in the format YYYY-MM-DD.
|
||||
| - | 2020-06-28 | Hallucinogenic Hypnotoad | v0.8.0.0 | v0.8.0.2 | Dandelion++ support
|
||||
| 253,999 | 2020-10-09 | Illiterate Illuminati | v0.9.0.0 | v0.9.3.3 | Dynamic coinbase unlock (up to 1 mo.), Deterministic unlock times, Enforce maximum coinbase amount, show_qr_code wallet command, CLSAG
|
||||
| 331,170 | 2021-07-04 | Junkie Jeff | v0.10.0.0 | v0.10.2.0 | Bulletproofs+, Miner Block Header Signing, Vote by Block, Change coinbase unlock time to 1 day, Reset difficulty and switch back to Monero's difficulty algorithm
|
||||
| 514,000 | 2023-04-01 | Kunty Karen | v0.11.0.0 | v0.11.0.0 | View tags, fee changes, adjusted dynamic block weight algorithm, multisig security fixes, RPC broadcast node donation sub-address, Limit tx_extra max size to ~1kb, 12-hour difficulty adjustment window
|
||||
| 514,000 | 2023-04-01 | Kunty Karen | v0.11.0.0 | v0.11.0.3 | View tags, fee changes, adjusted dynamic block weight algorithm, multisig security fixes, RPC broadcast node donation sub-address, Limit tx_extra max size to ~1kb, 12-hour difficulty adjustment window
|
||||
|
||||
X's indicate that these details have not been determined as of commit date.
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package=native_biplist
|
||||
$(package)_version=0.9
|
||||
$(package)_download_path=https://pypi.python.org/packages/source/b/biplist
|
||||
$(package)_file_name=biplist-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=b57cadfd26e4754efdf89e9e37de87885f9b5c847b2615688ca04adfaf6ca604
|
||||
$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages
|
||||
$(package)_patches=sorted_list.patch
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/sorted_list.patch
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
python setup.py build
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
mkdir -p $($(package)_install_libdir) && \
|
||||
python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
|
||||
endef
|
||||
@@ -1,26 +0,0 @@
|
||||
package=native_cdrkit
|
||||
$(package)_version=1.1.11
|
||||
$(package)_download_path=https://distro.ibiblio.org/fatdog/source/600/c
|
||||
$(package)_file_name=cdrkit-$($(package)_version).tar.bz2
|
||||
$(package)_sha256_hash=b50d64c214a65b1a79afe3a964c691931a4233e2ba605d793eb85d0ac3652564
|
||||
$(package)_patches=cdrkit-deterministic.patch
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/cdrkit-deterministic.patch
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$(build_prefix)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) genisoimage
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) -C genisoimage install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm bin/isovfy bin/isoinfo bin/isodump bin/isodebug bin/devdump
|
||||
endef
|
||||
@@ -1,23 +0,0 @@
|
||||
package=native_cmake
|
||||
$(package)_version=3.14.0
|
||||
$(package)_version_dot=v3.14
|
||||
$(package)_download_path=https://cmake.org/files/$($(package)_version_dot)/
|
||||
$(package)_file_name=cmake-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=aa76ba67b3c2af1946701f847073f4652af5cbd9f141f221c97af99127e75502
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./bootstrap &&\
|
||||
./configure $($(package)_config_opts)
|
||||
endef
|
||||
|
||||
define $(package)_build_cmd
|
||||
$(MAKE)
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
@@ -1,17 +0,0 @@
|
||||
package=native_ds_store
|
||||
$(package)_version=1.1.0
|
||||
$(package)_download_path=https://github.com/al45tair/ds_store/archive/
|
||||
$(package)_download_file=v$($(package)_version).tar.gz
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=a9f4c0755c6be7224ff7029e188dd262e830bb81e801424841db9eb0780ec8ed
|
||||
$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages
|
||||
$(package)_dependencies=native_biplist
|
||||
|
||||
define $(package)_build_cmds
|
||||
python setup.py build
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
mkdir -p $($(package)_install_libdir) && \
|
||||
python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
|
||||
endef
|
||||
@@ -1,22 +0,0 @@
|
||||
package=native_libdmg-hfsplus
|
||||
$(package)_version=0.1
|
||||
$(package)_download_path=https://github.com/theuni/libdmg-hfsplus/archive
|
||||
$(package)_file_name=libdmg-hfsplus-v$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=6569a02eb31c2827080d7d59001869ea14484c281efab0ae7f2b86af5c3120b3
|
||||
$(package)_build_subdir=build
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
mkdir build
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
cmake -DCMAKE_INSTALL_PREFIX:PATH=$(build_prefix)/bin ..
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) -C dmg
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) -C dmg install
|
||||
endef
|
||||
@@ -1,21 +0,0 @@
|
||||
package=native_mac_alias
|
||||
$(package)_version=1.1.0
|
||||
$(package)_download_path=https://github.com/al45tair/mac_alias/archive/
|
||||
$(package)_download_file=v$($(package)_version).tar.gz
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=b10cb44ecb64fc25283fae7a9cf365d2829377d84e37b9c21100aca8757509be
|
||||
$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages
|
||||
$(package)_patches=python3.patch
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/python3.patch
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
python setup.py build
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
mkdir -p $($(package)_install_libdir) && \
|
||||
python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir)
|
||||
endef
|
||||
@@ -1,67 +0,0 @@
|
||||
This file is part of MXE. See LICENSE.md for licensing information.
|
||||
|
||||
Contains ad hoc patches for cross building.
|
||||
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Theodore <tonyt@logyst.com>
|
||||
Date: Fri, 12 Aug 2016 02:01:20 +1000
|
||||
Subject: [PATCH 1/3] fix windres invocation options
|
||||
|
||||
windres doesn't recognise various gcc flags like -mms-bitfields,
|
||||
-fopenmp, -mthreads etc. (basically not `-D` or `-I`)
|
||||
|
||||
diff --git a/Modules/Platform/Windows-windres.cmake b/Modules/Platform/Windows-windres.cmake
|
||||
index 1111111..2222222 100644
|
||||
--- a/Modules/Platform/Windows-windres.cmake
|
||||
+++ b/Modules/Platform/Windows-windres.cmake
|
||||
@@ -1 +1 @@
|
||||
-set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff <DEFINES> <INCLUDES> <FLAGS> <SOURCE> <OBJECT>")
|
||||
+set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -O coff <DEFINES> <INCLUDES> <SOURCE> <OBJECT>")
|
||||
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Theodore <tonyt@logyst.com>
|
||||
Date: Tue, 25 Jul 2017 20:34:56 +1000
|
||||
Subject: [PATCH 2/3] add option to disable -isystem
|
||||
|
||||
taken from (not accepted):
|
||||
https://gitlab.kitware.com/cmake/cmake/merge_requests/895
|
||||
|
||||
see also:
|
||||
https://gitlab.kitware.com/cmake/cmake/issues/16291
|
||||
https://gitlab.kitware.com/cmake/cmake/issues/16919
|
||||
|
||||
diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake
|
||||
index 1111111..2222222 100644
|
||||
--- a/Modules/Compiler/GNU.cmake
|
||||
+++ b/Modules/Compiler/GNU.cmake
|
||||
@@ -42,7 +42,7 @@ macro(__compiler_gnu lang)
|
||||
string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG")
|
||||
set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -E <SOURCE> > <PREPROCESSED_SOURCE>")
|
||||
set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE "<CMAKE_${lang}_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -S <SOURCE> -o <ASSEMBLY_SOURCE>")
|
||||
- if(NOT APPLE OR NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4) # work around #4462
|
||||
+ if(NOT APPLE OR NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4 AND (NOT MXE_DISABLE_INCLUDE_SYSTEM_FLAG)) # work around #4462
|
||||
set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tony Theodore <tonyt@logyst.com>
|
||||
Date: Tue, 15 Aug 2017 15:25:06 +1000
|
||||
Subject: [PATCH 3/3] add CPACK_NSIS_EXECUTABLE variable
|
||||
|
||||
|
||||
diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx
|
||||
index 1111111..2222222 100644
|
||||
--- a/Source/CPack/cmCPackNSISGenerator.cxx
|
||||
+++ b/Source/CPack/cmCPackNSISGenerator.cxx
|
||||
@@ -384,7 +384,9 @@ int cmCPackNSISGenerator::InitializeInternal()
|
||||
}
|
||||
#endif
|
||||
|
||||
- nsisPath = cmSystemTools::FindProgram("makensis", path, false);
|
||||
+ this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLE", "makensis");
|
||||
+ nsisPath = cmSystemTools::FindProgram(
|
||||
+ this->GetOption("CPACK_NSIS_EXECUTABLE"), path, false);
|
||||
|
||||
if (nsisPath.empty()) {
|
||||
cmCPackLogger(
|
||||
@@ -1,29 +0,0 @@
|
||||
--- a/biplist/__init__.py 2014-10-26 19:03:11.000000000 +0000
|
||||
+++ b/biplist/__init__.py 2016-07-19 19:30:17.663521999 +0000
|
||||
@@ -541,7 +541,7 @@
|
||||
return HashableWrapper(n)
|
||||
elif isinstance(root, dict):
|
||||
n = {}
|
||||
- for key, value in iteritems(root):
|
||||
+ for key, value in sorted(iteritems(root)):
|
||||
n[self.wrapRoot(key)] = self.wrapRoot(value)
|
||||
return HashableWrapper(n)
|
||||
elif isinstance(root, list):
|
||||
@@ -616,7 +616,7 @@
|
||||
elif isinstance(obj, dict):
|
||||
size = proc_size(len(obj))
|
||||
self.incrementByteCount('dictBytes', incr=1+size)
|
||||
- for key, value in iteritems(obj):
|
||||
+ for key, value in sorted(iteritems(obj)):
|
||||
check_key(key)
|
||||
self.computeOffsets(key, asReference=True)
|
||||
self.computeOffsets(value, asReference=True)
|
||||
@@ -714,7 +714,7 @@
|
||||
keys = []
|
||||
values = []
|
||||
objectsToWrite = []
|
||||
- for key, value in iteritems(obj):
|
||||
+ for key, value in sorted(iteritems(obj)):
|
||||
keys.append(key)
|
||||
values.append(value)
|
||||
for key in keys:
|
||||
@@ -1,86 +0,0 @@
|
||||
--- cdrkit-1.1.11.old/genisoimage/tree.c 2008-10-21 19:57:47.000000000 -0400
|
||||
+++ cdrkit-1.1.11/genisoimage/tree.c 2013-12-06 00:23:18.489622668 -0500
|
||||
@@ -1139,8 +1139,9 @@
|
||||
scan_directory_tree(struct directory *this_dir, char *path,
|
||||
struct directory_entry *de)
|
||||
{
|
||||
- DIR *current_dir;
|
||||
+ int current_file;
|
||||
char whole_path[PATH_MAX];
|
||||
+ struct dirent **d_list;
|
||||
struct dirent *d_entry;
|
||||
struct directory *parent;
|
||||
int dflag;
|
||||
@@ -1164,7 +1165,8 @@
|
||||
this_dir->dir_flags |= DIR_WAS_SCANNED;
|
||||
|
||||
errno = 0; /* Paranoia */
|
||||
- current_dir = opendir(path);
|
||||
+ //current_dir = opendir(path);
|
||||
+ current_file = scandir(path, &d_list, NULL, alphasort);
|
||||
d_entry = NULL;
|
||||
|
||||
/*
|
||||
@@ -1173,12 +1175,12 @@
|
||||
*/
|
||||
old_path = path;
|
||||
|
||||
- if (current_dir) {
|
||||
+ if (current_file >= 0) {
|
||||
errno = 0;
|
||||
- d_entry = readdir(current_dir);
|
||||
+ d_entry = d_list[0];
|
||||
}
|
||||
|
||||
- if (!current_dir || !d_entry) {
|
||||
+ if (current_file < 0 || !d_entry) {
|
||||
int ret = 1;
|
||||
|
||||
#ifdef USE_LIBSCHILY
|
||||
@@ -1191,8 +1193,8 @@
|
||||
de->isorec.flags[0] &= ~ISO_DIRECTORY;
|
||||
ret = 0;
|
||||
}
|
||||
- if (current_dir)
|
||||
- closedir(current_dir);
|
||||
+ if(d_list)
|
||||
+ free(d_list);
|
||||
return (ret);
|
||||
}
|
||||
#ifdef ABORT_DEEP_ISO_ONLY
|
||||
@@ -1208,7 +1210,7 @@
|
||||
errmsgno(EX_BAD, "use Rock Ridge extensions via -R or -r,\n");
|
||||
errmsgno(EX_BAD, "or allow deep ISO9660 directory nesting via -D.\n");
|
||||
}
|
||||
- closedir(current_dir);
|
||||
+ free(d_list);
|
||||
return (1);
|
||||
}
|
||||
#endif
|
||||
@@ -1250,13 +1252,13 @@
|
||||
* The first time through, skip this, since we already asked
|
||||
* for the first entry when we opened the directory.
|
||||
*/
|
||||
- if (dflag)
|
||||
- d_entry = readdir(current_dir);
|
||||
+ if (dflag && current_file >= 0)
|
||||
+ d_entry = d_list[current_file];
|
||||
dflag++;
|
||||
|
||||
- if (!d_entry)
|
||||
+ if (current_file < 0)
|
||||
break;
|
||||
-
|
||||
+ current_file--;
|
||||
/* OK, got a valid entry */
|
||||
|
||||
/* If we do not want all files, then pitch the backups. */
|
||||
@@ -1348,7 +1350,7 @@
|
||||
insert_file_entry(this_dir, whole_path, d_entry->d_name);
|
||||
#endif /* APPLE_HYB */
|
||||
}
|
||||
- closedir(current_dir);
|
||||
+ free(d_list);
|
||||
|
||||
#ifdef APPLE_HYB
|
||||
/*
|
||||
@@ -1,72 +0,0 @@
|
||||
diff -dur a/mac_alias/alias.py b/mac_alias/alias.py
|
||||
--- a/mac_alias/alias.py 2015-10-19 12:12:48.000000000 +0200
|
||||
+++ b/mac_alias/alias.py 2016-04-03 12:13:12.037159417 +0200
|
||||
@@ -243,10 +243,10 @@
|
||||
alias = Alias()
|
||||
alias.appinfo = appinfo
|
||||
|
||||
- alias.volume = VolumeInfo (volname.replace('/',':'),
|
||||
+ alias.volume = VolumeInfo (volname.decode().replace('/',':'),
|
||||
voldate, fstype, disktype,
|
||||
volattrs, volfsid)
|
||||
- alias.target = TargetInfo (kind, filename.replace('/',':'),
|
||||
+ alias.target = TargetInfo (kind, filename.decode().replace('/',':'),
|
||||
folder_cnid, cnid,
|
||||
crdate, creator_code, type_code)
|
||||
alias.target.levels_from = levels_from
|
||||
@@ -261,9 +261,9 @@
|
||||
b.read(1)
|
||||
|
||||
if tag == TAG_CARBON_FOLDER_NAME:
|
||||
- alias.target.folder_name = value.replace('/',':')
|
||||
+ alias.target.folder_name = value.decode().replace('/',':')
|
||||
elif tag == TAG_CNID_PATH:
|
||||
- alias.target.cnid_path = struct.unpack(b'>%uI' % (length // 4),
|
||||
+ alias.target.cnid_path = struct.unpack('>%uI' % (length // 4),
|
||||
value)
|
||||
elif tag == TAG_CARBON_PATH:
|
||||
alias.target.carbon_path = value
|
||||
@@ -298,9 +298,9 @@
|
||||
alias.target.creation_date \
|
||||
= mac_epoch + datetime.timedelta(seconds=seconds)
|
||||
elif tag == TAG_POSIX_PATH:
|
||||
- alias.target.posix_path = value
|
||||
+ alias.target.posix_path = value.decode()
|
||||
elif tag == TAG_POSIX_PATH_TO_MOUNTPOINT:
|
||||
- alias.volume.posix_path = value
|
||||
+ alias.volume.posix_path = value.decode()
|
||||
elif tag == TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE:
|
||||
alias.volume.disk_image_alias = Alias.from_bytes(value)
|
||||
elif tag == TAG_USER_HOME_LENGTH_PREFIX:
|
||||
@@ -422,13 +422,13 @@
|
||||
# (so doing so is ridiculous, and nothing could rely on it).
|
||||
b.write(struct.pack(b'>h28pI2shI64pII4s4shhI2s10s',
|
||||
self.target.kind,
|
||||
- carbon_volname, voldate,
|
||||
+ carbon_volname, int(voldate),
|
||||
self.volume.fs_type,
|
||||
self.volume.disk_type,
|
||||
self.target.folder_cnid,
|
||||
carbon_filename,
|
||||
self.target.cnid,
|
||||
- crdate,
|
||||
+ int(crdate),
|
||||
self.target.creator_code,
|
||||
self.target.type_code,
|
||||
self.target.levels_from,
|
||||
@@ -449,12 +449,12 @@
|
||||
|
||||
b.write(struct.pack(b'>hhQhhQ',
|
||||
TAG_HIGH_RES_VOLUME_CREATION_DATE,
|
||||
- 8, long(voldate * 65536),
|
||||
+ 8, int(voldate * 65536),
|
||||
TAG_HIGH_RES_CREATION_DATE,
|
||||
- 8, long(crdate * 65536)))
|
||||
+ 8, int(crdate * 65536)))
|
||||
|
||||
if self.target.cnid_path:
|
||||
- cnid_path = struct.pack(b'>%uI' % len(self.target.cnid_path),
|
||||
+ cnid_path = struct.pack('>%uI' % len(self.target.cnid_path),
|
||||
*self.target.cnid_path)
|
||||
b.write(struct.pack(b'>hh', TAG_CNID_PATH,
|
||||
len(cnid_path)))
|
||||
Binary file not shown.
@@ -235,6 +235,10 @@ namespace cryptonote
|
||||
ADD_CHECKPOINT2(497100, "2c4c70ac1ada94151f19d67ccf1aa4e846e6067f49f67c85cc03f78e768ea42b", "0x116906bc97a751");
|
||||
ADD_CHECKPOINT2(500000, "f4f771261b8c13cd83a9d8fa22e3cfe988564ad4b57dd90e79d5c0e77d61cf6a", "0x1185e7f2357a03");
|
||||
ADD_CHECKPOINT2(503500, "776f36a17056c3e22bbfb51d5aeabb58000731e9ad549f0f2f8ad1e1bcedf312", "0x11a4884467f53d");
|
||||
ADD_CHECKPOINT2(509900, "59520faa272fc68e0426c827a38b21cdc1df8f5a37c5fdcbbe00350fece5f3ae", "0x11dc780bd1b580");
|
||||
ADD_CHECKPOINT2(514000, "1569e712750f19e57aee3f73cc3091a0eea392740bd396ad3570bc96e0e6ffb5", "0x11fff58abe0a82"); //Hard fork to v20
|
||||
ADD_CHECKPOINT2(516700, "0443c47c5a4e344c3f68a491a3b2f6b78a769cdf9076249c93f187ececf9cc7c", "0x12128a532a59a6");
|
||||
ADD_CHECKPOINT2(522000, "8c15ae514063bf05e7662ab33b86a4131aa89df0784ce3da7876c5339bc1de3d", "0x123d9c604a7be6");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -280,6 +284,7 @@ namespace cryptonote
|
||||
|
||||
// All four MoneroPulse domains have DNSSEC on and valid
|
||||
static const std::vector<std::string> dns_urls = {
|
||||
"checkpoints.muchwow.lol",
|
||||
};
|
||||
|
||||
static const std::vector<std::string> testnet_dns_urls = {
|
||||
|
||||
@@ -526,12 +526,12 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std
|
||||
const std::string &url = dns_urls[cur_index];
|
||||
if (!avail[cur_index])
|
||||
{
|
||||
records[cur_index].clear();
|
||||
//records[cur_index].clear(); TODO: temp skipped DNSSEC
|
||||
LOG_PRINT_L2("DNSSEC not available for hostname: " << url << ", skipping.");
|
||||
}
|
||||
if (!valid[cur_index])
|
||||
{
|
||||
records[cur_index].clear();
|
||||
//records[cur_index].clear(); TODO: temp skipped DNSSEC
|
||||
LOG_PRINT_L2("DNSSEC validation failed for hostname: " << url << ", skipping.");
|
||||
}
|
||||
|
||||
@@ -552,7 +552,7 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std
|
||||
}
|
||||
}
|
||||
|
||||
if (num_valid_records < 2)
|
||||
if (num_valid_records < 1)
|
||||
{
|
||||
LOG_PRINT_L2("WARNING: no two valid DNS TXT records were received");
|
||||
return false;
|
||||
|
||||
@@ -1067,7 +1067,7 @@ std::string get_nix_version_display_string()
|
||||
time_t tt = ts;
|
||||
struct tm tm;
|
||||
misc_utils::get_gmt_time(tt, tm);
|
||||
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tm);
|
||||
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%SZ", &tm);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,10 +42,11 @@
|
||||
#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)) != -1L)
|
||||
#define CTHR_THREAD_JOIN(thr) WaitForSingleObject((HANDLE)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
|
||||
|
||||
@@ -64,5 +65,6 @@
|
||||
#define CTHR_THREAD_RETURN return NULL
|
||||
#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
|
||||
|
||||
@@ -332,7 +332,7 @@ static void rx_init_dataset(size_t max_threads) {
|
||||
local_abort("Couldn't start RandomX seed thread");
|
||||
}
|
||||
}
|
||||
rx_seedthread(&si[n1]);
|
||||
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);
|
||||
|
||||
@@ -402,6 +402,7 @@ void rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads)
|
||||
if (!CTHR_THREAD_CREATE(t, rx_set_main_seedhash_thread, info)) {
|
||||
local_abort("Couldn't start RandomX seed thread");
|
||||
}
|
||||
CTHR_THREAD_CLOSE(t);
|
||||
}
|
||||
|
||||
void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash) {
|
||||
|
||||
@@ -39,15 +39,6 @@ namespace cryptonote {
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
template<class t_array>
|
||||
struct array_hasher: std::unary_function<t_array&, std::size_t>
|
||||
{
|
||||
std::size_t operator()(const t_array& val) const
|
||||
{
|
||||
return boost::hash_range(&val.data[0], &val.data[sizeof(val.data)]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct public_address_outer_blob
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
#define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000
|
||||
#define P2P_LOCAL_GRAY_PEERLIST_LIMIT 5000
|
||||
|
||||
#define P2P_DEFAULT_CONNECTIONS_COUNT 64
|
||||
#define P2P_DEFAULT_CONNECTIONS_COUNT 12
|
||||
#define P2P_DEFAULT_HANDSHAKE_INTERVAL 60 //secondes
|
||||
#define P2P_DEFAULT_PACKET_MAX_SIZE 50000000 //50000000 bytes maximum packet size
|
||||
#define P2P_DEFAULT_PEERS_IN_HANDSHAKE 250
|
||||
@@ -154,8 +154,8 @@
|
||||
#define P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT 70
|
||||
#define P2P_DEFAULT_ANCHOR_CONNECTIONS_COUNT 2
|
||||
#define P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT 2
|
||||
#define P2P_DEFAULT_LIMIT_RATE_UP 1048576 // 1GB/s
|
||||
#define P2P_DEFAULT_LIMIT_RATE_DOWN 1048576 // 1GB/s
|
||||
#define P2P_DEFAULT_LIMIT_RATE_UP 2048 // kB/s
|
||||
#define P2P_DEFAULT_LIMIT_RATE_DOWN 8192 // kB/s
|
||||
|
||||
#define P2P_FAILED_ADDR_FORGET_SECONDS (60*60) //1 hour
|
||||
#define P2P_IP_BLOCKTIME (60*60*24) //24 hour
|
||||
@@ -265,6 +265,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};
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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__);
|
||||
}
|
||||
@@ -3322,7 +3324,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");
|
||||
@@ -3645,6 +3647,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)
|
||||
@@ -3666,12 +3675,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...
|
||||
@@ -3690,61 +3693,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::verRctNonSemanticsSimpleCached(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;
|
||||
@@ -3754,6 +3703,12 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
case rct::RCTTypeFull:
|
||||
case rct::RCTTypeFullBulletproof:
|
||||
{
|
||||
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;
|
||||
@@ -5747,7 +5702,7 @@ void Blockchain::cancel()
|
||||
}
|
||||
|
||||
#if defined(PER_BLOCK_CHECKPOINT)
|
||||
static const char expected_block_hashes_hash[] = "758b237b54248c7d47c699156ea8a77db0dc04cc4f89783cc2b1a5b1a9658e18";
|
||||
static const char expected_block_hashes_hash[] = "ba330ed9cd10aabcbfd4a501d5271caecc56999fe4b2863d6c99f871b7282014";
|
||||
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
|
||||
{
|
||||
if (get_checkpoints == nullptr || !m_fast_sync)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -1103,7 +1103,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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -225,6 +226,7 @@ namespace cryptonote
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
167
src/cryptonote_core/tx_verification_utils.cpp
Normal file
167
src/cryptonote_core/tx_verification_utils.cpp
Normal file
@@ -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
|
||||
78
src/cryptonote_core/tx_verification_utils.h
Normal file
78
src/cryptonote_core/tx_verification_utils.h
Normal file
@@ -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);
|
||||
|
||||
@@ -219,6 +219,19 @@ int main(int argc, char const * argv[])
|
||||
{
|
||||
po::store(po::parse_config_file<char>(config_path.string<std::string>().c_str(), core_settings), vm);
|
||||
}
|
||||
catch (const po::unknown_option &e)
|
||||
{
|
||||
std::string unrecognized_option = e.get_option_name();
|
||||
if (all_options.find_nothrow(unrecognized_option, false))
|
||||
{
|
||||
std::cerr << "Option '" << unrecognized_option << "' is not allowed in the config file, please use it as a command line flag." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Unrecognized option '" << unrecognized_option << "' in config file." << std::endl;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
// log system isn't initialized yet
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -48,7 +48,7 @@ const hardfork_t mainnet_hard_forks[] = {
|
||||
{ 20, 514000, 0, 1677222289 },
|
||||
};
|
||||
// since Wownero starts from v7, added + 6 so that the total number of hard forks = version number
|
||||
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]) + 6;
|
||||
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
|
||||
const uint64_t mainnet_hard_fork_version_1_till = 0;
|
||||
|
||||
const hardfork_t testnet_hard_forks[] = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
@@ -694,15 +714,15 @@ namespace nodetool
|
||||
}
|
||||
else
|
||||
{
|
||||
full_addrs.insert("158.69.60.225:34567"); // explore.wownero.com
|
||||
full_addrs.insert("159.65.91.59:34567"); // jw
|
||||
full_addrs.insert("51.161.131.176:34567"); // node.suchwow.xyz
|
||||
full_addrs.insert("167.114.196.241:34567"); // wowbux.org
|
||||
full_addrs.insert("142.93.144.79:34567"); // idontwanttogototoronto.wow.fail
|
||||
full_addrs.insert("51.75.76.161:34567"); // eu-west-1.wow.xmr.pm
|
||||
full_addrs.insert("145.239.93.75:34567"); // eu-west-2.wow.xmr.pm
|
||||
full_addrs.insert("88.198.199.23:34567");
|
||||
full_addrs.insert("167.114.119.46:34567"); // wownero.stackwallet.com
|
||||
//full_addrs.insert("158.69.60.225:34567"); // explore.wownero.com
|
||||
//full_addrs.insert("159.65.91.59:34567"); // jw
|
||||
//full_addrs.insert("51.161.131.176:34567"); // node.suchwow.xyz
|
||||
//full_addrs.insert("167.114.196.241:34567"); // wowbux.org
|
||||
//full_addrs.insert("142.93.144.79:34567"); // idontwanttogototoronto.wow.fail
|
||||
//full_addrs.insert("51.75.76.161:34567"); // eu-west-1.wow.xmr.pm
|
||||
//full_addrs.insert("145.239.93.75:34567"); // eu-west-2.wow.xmr.pm
|
||||
//full_addrs.insert("88.198.199.23:34567");
|
||||
//full_addrs.insert("167.114.119.46:34567"); // wownero.stackwallet.com
|
||||
full_addrs.insert("143.198.195.132:34567"); // singapore.muchwow.lol
|
||||
full_addrs.insert("134.122.53.193:34567"); // amsterdam.muchwow.lol
|
||||
full_addrs.insert("204.48.28.218:34567"); // nyc.muchwow.lol
|
||||
@@ -1998,12 +2018,14 @@ namespace nodetool
|
||||
template<class t_payload_net_handler>
|
||||
bool node_server<t_payload_net_handler>::update_dns_blocklist()
|
||||
{
|
||||
if (!m_enable_dns_blocklist)
|
||||
return true;
|
||||
/*if (!m_enable_dns_blocklist) // TODO: temp forced DNS blocklist
|
||||
return true;*/
|
||||
if (m_nettype != cryptonote::MAINNET)
|
||||
return true;
|
||||
|
||||
static const std::vector<std::string> dns_urls = {
|
||||
"blocklist.wownero.com",
|
||||
"blocklist2.wownero.com",
|
||||
};
|
||||
|
||||
std::vector<std::string> records;
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
|
||||
#include "misc_log_ex.h"
|
||||
#include "misc_language.h"
|
||||
#include "common/data_cache.h"
|
||||
#include "common/perf_timer.h"
|
||||
#include "common/threadpool.h"
|
||||
#include "common/util.h"
|
||||
@@ -1578,7 +1577,7 @@ namespace rct {
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(rvp, false, "rctSig pointer is NULL");
|
||||
const rctSig &rv = *rvp;
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus,
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus,
|
||||
false, "verRctSemanticsSimple called on non simple rctSig");
|
||||
const bool bulletproof = is_rct_bulletproof(rv.type);
|
||||
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type);
|
||||
@@ -1710,7 +1709,7 @@ namespace rct {
|
||||
{
|
||||
PERF_TIMER(verRctNonSemanticsSimple);
|
||||
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus,
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus,
|
||||
false, "verRctNonSemanticsSimple called on non simple rctSig");
|
||||
const bool bulletproof = is_rct_bulletproof(rv.type);
|
||||
const bool bulletproof_plus = is_rct_bulletproof_plus(rv.type);
|
||||
@@ -1765,42 +1764,6 @@ namespace rct {
|
||||
}
|
||||
}
|
||||
|
||||
bool verRctNonSemanticsSimpleCached(const rctSig & rv)
|
||||
{
|
||||
// Hello future Monero dev! If you got this assert, read the following carefully:
|
||||
//
|
||||
// RCT cache assumes that this function will serialize and hash all rv's fields used for RingCT verification
|
||||
// If you're about to add a new RCTType here, first you must check that binary_archive serialization writes all rv's fields to the binary blob
|
||||
// If it's not the case, rewrite this function to serialize everything, even some "temporary" fields which are not serialized normally
|
||||
CHECK_AND_ASSERT_MES_L1(rv.type <= RCTTypeBulletproofPlus, false, "Unknown RCT 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 (rv.type != RCTTypeBulletproofPlus)
|
||||
return verRctNonSemanticsSimple(rv);
|
||||
|
||||
// Get the hash of rv
|
||||
std::stringstream ss;
|
||||
binary_archive<true> ar(ss);
|
||||
|
||||
::do_serialize(ar, const_cast<rctSig&>(rv));
|
||||
|
||||
crypto::hash h;
|
||||
cryptonote::get_blob_hash(ss.str(), h);
|
||||
|
||||
static tools::data_cache<crypto::hash, 8192> cache;
|
||||
|
||||
if (cache.has(h))
|
||||
return true;
|
||||
|
||||
const bool res = verRctNonSemanticsSimple(rv);
|
||||
if (res)
|
||||
cache.add(h);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//RingCT protocol
|
||||
//genRct:
|
||||
// creates an rctSig with all data necessary to verify the rangeProofs and that the signer owns one of the
|
||||
@@ -1844,7 +1807,7 @@ namespace rct {
|
||||
}
|
||||
|
||||
xmr_amount decodeRctSimple(const rctSig & rv, const key & sk, unsigned int i, key &mask, hw::device &hwdev) {
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus,
|
||||
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple || rv.type == RCTTypeBulletproof || rv.type == RCTTypeBulletproof2 || rv.type == RCTTypeSimpleBulletproof || rv.type == RCTTypeCLSAG || rv.type == RCTTypeBulletproofPlus,
|
||||
false, "decodeRct called on non simple rctSig");
|
||||
CHECK_AND_ASSERT_THROW_MES(i < rv.ecdhInfo.size(), "Bad index");
|
||||
CHECK_AND_ASSERT_THROW_MES(rv.outPk.size() == rv.ecdhInfo.size(), "Mismatched sizes of rv.outPk and rv.ecdhInfo");
|
||||
|
||||
@@ -135,7 +135,6 @@ namespace rct {
|
||||
bool verRctSemanticsSimple(const rctSig & rv);
|
||||
bool verRctSemanticsSimple(const std::vector<const rctSig*> & rv);
|
||||
bool verRctNonSemanticsSimple(const rctSig & rv);
|
||||
bool verRctNonSemanticsSimpleCached(const rctSig & rv);
|
||||
static inline bool verRctSimple(const rctSig & rv) { return verRctSemanticsSimple(rv) && verRctNonSemanticsSimple(rv); }
|
||||
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev);
|
||||
xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, hw::device &hwdev);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1251,6 +1251,7 @@ namespace cryptonote
|
||||
{
|
||||
LOG_PRINT_L0("[on_send_raw_tx]: Failed to parse tx from hexbuff: " << req.tx_as_hex);
|
||||
res.status = "Failed";
|
||||
res.reason = "Hex decoding failed";
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_MONERO_VERSION "0.11.0.0"
|
||||
#define DEF_MONERO_VERSION "0.11.0.3"
|
||||
#define DEF_MONERO_RELEASE_NAME "Kunty Karen"
|
||||
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG
|
||||
#define DEF_MONERO_VERSION_IS_RELEASE @VERSION_IS_RELEASE@
|
||||
|
||||
@@ -1208,8 +1208,8 @@ UnsignedTransaction *WalletImpl::loadUnsignedTxFromStr(const std::string &unsign
|
||||
|
||||
// Check tx data and construct confirmation message
|
||||
std::string extra_message;
|
||||
if (!transaction->m_unsigned_tx_set.transfers.second.empty())
|
||||
extra_message = (boost::format("%u outputs to import. ") % (unsigned)transaction->m_unsigned_tx_set.transfers.second.size()).str();
|
||||
if (!std::get<2>(transaction->m_unsigned_tx_set.transfers).empty())
|
||||
extra_message = (boost::format("%u outputs to import. ") % (unsigned)std::get<2>(transaction->m_unsigned_tx_set.transfers).size()).str();
|
||||
transaction->checkLoadedTx([&transaction](){return transaction->m_unsigned_tx_set.txes.size();}, [&transaction](size_t n)->const tools::wallet2::tx_construction_data&{return transaction->m_unsigned_tx_set.txes[n];}, extra_message);
|
||||
setStatus(transaction->status(), transaction->errorString());
|
||||
|
||||
@@ -2078,7 +2078,6 @@ uint64_t WalletImpl::estimateTransactionFee(const std::vector<std::pair<std::str
|
||||
extra_size,
|
||||
m_wallet->use_fork_rules(8, 0),
|
||||
m_wallet->use_fork_rules(HF_VERSION_CLSAG, 0),
|
||||
true,
|
||||
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(priority),
|
||||
|
||||
@@ -2945,16 +2945,20 @@ void check_block_hard_fork_version(cryptonote::network_type nettype, uint8_t hf_
|
||||
const hardfork_t *wallet_hard_forks = nettype == TESTNET ? testnet_hard_forks
|
||||
: nettype == STAGENET ? stagenet_hard_forks : mainnet_hard_forks;
|
||||
|
||||
wallet_is_outdated = static_cast<size_t>(hf_version) > wallet_num_hard_forks;
|
||||
wallet_is_outdated = hf_version > wallet_hard_forks[wallet_num_hard_forks-1].version;
|
||||
if (wallet_is_outdated)
|
||||
return;
|
||||
|
||||
// check block's height falls within wallet's expected range for block's given version
|
||||
// Wownero version 7 starts from block 0
|
||||
uint64_t start_height = hf_version == 7 ? 0 : wallet_hard_forks[hf_version - 7].height;
|
||||
uint64_t end_height = static_cast<size_t>(hf_version) + 1 > wallet_num_hard_forks
|
||||
size_t fork_index;
|
||||
for (fork_index = 0; fork_index < wallet_num_hard_forks; ++fork_index)
|
||||
if (wallet_hard_forks[fork_index].version == hf_version)
|
||||
break;
|
||||
THROW_WALLET_EXCEPTION_IF(fork_index == wallet_num_hard_forks, error::wallet_internal_error, "Fork not found in table");
|
||||
uint64_t start_height = wallet_hard_forks[fork_index].height;
|
||||
uint64_t end_height = fork_index == wallet_num_hard_forks - 1
|
||||
? std::numeric_limits<uint64_t>::max()
|
||||
: wallet_hard_forks[hf_version - 6].height;
|
||||
: wallet_hard_forks[fork_index + 1].height;
|
||||
|
||||
daemon_is_outdated = height < start_height || height >= end_height;
|
||||
}
|
||||
@@ -3847,7 +3851,7 @@ void wallet2::detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, ui
|
||||
transfers_detached = std::distance(it, m_transfers.end());
|
||||
m_transfers.erase(it, m_transfers.end());
|
||||
|
||||
size_t blocks_detached = m_blockchain.size() - height;
|
||||
const uint64_t blocks_detached = m_blockchain.size() - height;
|
||||
m_blockchain.crop(height);
|
||||
|
||||
for (auto it = m_payments.begin(); it != m_payments.end(); )
|
||||
@@ -3866,6 +3870,9 @@ void wallet2::detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, ui
|
||||
++it;
|
||||
}
|
||||
|
||||
if (m_callback)
|
||||
m_callback->on_reorg(height, blocks_detached, transfers_detached);
|
||||
|
||||
LOG_PRINT_L0("Detached blockchain on height " << height << ", transfers detached " << transfers_detached << ", blocks detached " << blocks_detached);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
@@ -6926,6 +6933,24 @@ void wallet2::commit_tx(pending_tx& ptx)
|
||||
crypto::hash txid;
|
||||
|
||||
txid = get_transaction_hash(ptx.tx);
|
||||
|
||||
// if it's already processed, bail
|
||||
if (std::find_if(m_transfers.begin(), m_transfers.end(), [&txid](const transfer_details &td) { return td.m_txid == txid; }) != m_transfers.end())
|
||||
{
|
||||
MDEBUG("Transaction " << txid << " already processed");
|
||||
return;
|
||||
}
|
||||
if (m_unconfirmed_txs.find(txid) != m_unconfirmed_txs.end())
|
||||
{
|
||||
MDEBUG("Transaction " << txid << " already processed");
|
||||
return;
|
||||
}
|
||||
if (m_confirmed_txs.find(txid) != m_confirmed_txs.end())
|
||||
{
|
||||
MDEBUG("Transaction " << txid << " already processed");
|
||||
return;
|
||||
}
|
||||
|
||||
crypto::hash payment_id = crypto::null_hash;
|
||||
std::vector<cryptonote::tx_destination_entry> dests;
|
||||
uint64_t amount_in = 0;
|
||||
@@ -8597,8 +8622,8 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
|
||||
// check we're clear enough of rct start, to avoid corner cases below
|
||||
THROW_WALLET_EXCEPTION_IF(rct_offsets.size() <= CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE,
|
||||
error::get_output_distribution, "Not enough rct outputs");
|
||||
THROW_WALLET_EXCEPTION_IF(rct_offsets.back() <= max_rct_index,
|
||||
error::get_output_distribution, "Daemon reports suspicious number of rct outputs");
|
||||
//THROW_WALLET_EXCEPTION_IF(rct_offsets.back() <= max_rct_index,
|
||||
//error::get_output_distribution, "Daemon reports suspicious number of rct outputs");
|
||||
}
|
||||
|
||||
// get histogram for the amounts we need
|
||||
|
||||
@@ -138,6 +138,7 @@ private:
|
||||
public:
|
||||
// Full wallet callbacks
|
||||
virtual void on_new_block(uint64_t height, const cryptonote::block& block) {}
|
||||
virtual void on_reorg(uint64_t height, uint64_t blocks_detached, size_t transfers_detached) {}
|
||||
virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, uint64_t burnt, const cryptonote::subaddress_index& subaddr_index, bool is_change, uint64_t unlock_time) {}
|
||||
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {}
|
||||
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index) {}
|
||||
|
||||
@@ -576,9 +576,9 @@ namespace tools
|
||||
if (!m_wallet) return not_open(er);
|
||||
try
|
||||
{
|
||||
if (req.count < 1 || req.count > 64) {
|
||||
if (req.count < 1 || req.count > 65536) {
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = "Count must be between 1 and 64.";
|
||||
er.message = "Count must be between 1 and 65536.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BIN
tests/data/txs/bpp_tx_e89415.bin
Normal file
BIN
tests/data/txs/bpp_tx_e89415.bin
Normal file
Binary file not shown.
@@ -52,6 +52,7 @@ class TransferTest():
|
||||
self.check_tx_notes()
|
||||
self.check_rescan()
|
||||
self.check_is_key_image_spent()
|
||||
self.check_multiple_submissions()
|
||||
|
||||
def reset(self):
|
||||
print('Resetting blockchain')
|
||||
@@ -829,6 +830,39 @@ class TransferTest():
|
||||
res = daemon.is_key_image_spent(ki)
|
||||
assert res.spent_status == expected
|
||||
|
||||
def check_multiple_submissions(self):
|
||||
daemon = Daemon()
|
||||
|
||||
print('Testing multiple submissions')
|
||||
|
||||
dst = {'address': '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', 'amount': 1000000000000}
|
||||
|
||||
self.wallet[0].refresh()
|
||||
res = self.wallet[0].get_balance()
|
||||
balance = res.balance
|
||||
|
||||
res = self.wallet[0].transfer([dst], ring_size = 16, get_tx_key = False, get_tx_hex = False, get_tx_metadata = True)
|
||||
tx_hex = res.tx_metadata
|
||||
tx_fee = res.fee
|
||||
res = self.wallet[0].relay_tx(tx_hex)
|
||||
|
||||
# submit again before mined
|
||||
res = self.wallet[0].relay_tx(tx_hex)
|
||||
daemon.generateblocks('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 1)
|
||||
|
||||
self.wallet[0].refresh()
|
||||
res = self.wallet[0].get_balance()
|
||||
assert res.balance == balance - tx_fee
|
||||
|
||||
balance = res.balance
|
||||
|
||||
# submit again after mined
|
||||
res = self.wallet[0].relay_tx(tx_hex)
|
||||
daemon.generateblocks('44Kbx4sJ7JDRDV5aAhLJzQCjDz2ViLRduE3ijDZu3osWKBjMGkV1XPk4pfDUMqt1Aiezvephdqm6YD19GKFD9ZcXVUTp6BW', 1)
|
||||
|
||||
self.wallet[0].refresh()
|
||||
res = self.wallet[0].get_balance()
|
||||
assert res.balance == balance
|
||||
|
||||
if __name__ == '__main__':
|
||||
TransferTest().run_test()
|
||||
|
||||
@@ -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
|
||||
|
||||
426
tests/unit_tests/ver_rct_non_semantics_simple_cached.cpp
Normal file
426
tests/unit_tests/ver_rct_non_semantics_simple_cached.cpp
Normal file
@@ -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]++)
|
||||
}
|
||||
@@ -1,45 +1,52 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
=/hgc
|
||||
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
|
||||
/Q6sM4xf2Y0=
|
||||
=QKTj
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
Reference in New Issue
Block a user