mirror of
https://git.wownero.com/wownero/wownero.git
synced 2024-08-15 01:03:23 +00:00
Merge pull request 'upstream' (#469) from wowario/wownero:wow-v0.11 into master
Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/469
This commit is contained in:
commit
a21819cc22
30 changed files with 760 additions and 525 deletions
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: |
|
||||
|
|
|
@ -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)))
|
BIN
src/blocks/checkpoints.dat
Normal file
BIN
src/blocks/checkpoints.dat
Normal file
Binary file not shown.
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
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
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------
|
||||
|
|
|
@ -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"
|
||||
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
BIN
tests/data/txs/bpp_tx_e89415.bin
Normal file
BIN
tests/data/txs/bpp_tx_e89415.bin
Normal file
Binary file not shown.
|
@ -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]++)
|
||||
}
|
Loading…
Reference in a new issue