Compare commits
228 Commits
v0.9.9-rc1
...
v1.1.1
| Author | SHA1 | Date | |
|---|---|---|---|
| b57d2c338c | |||
| 28069fc84b | |||
| d7ec62cdbe | |||
| 244fc7acaa | |||
| 3716330ac7 | |||
| c4e7f6e0f0 | |||
| c0862ea66e | |||
| 67b41240d2 | |||
| 16110603a1 | |||
| 83934efaad | |||
| 6fb167308c | |||
| d6f95156bc | |||
| 35804afc90 | |||
| bc59547714 | |||
| f2b6068d8b | |||
| c820967cba | |||
| eadaa21e83 | |||
| 465b384195 | |||
| 768ca26a8d | |||
| 6fb131a52b | |||
| 3f18c388f6 | |||
| 2f646cdc10 | |||
| a5523be459 | |||
| 81d322b2ce | |||
| 3b1a939417 | |||
| a4e7ebc591 | |||
| 25dccd5423 | |||
| d05ac7f44e | |||
| 35b1a03b3d | |||
| 7acf8068ea | |||
| 383f3d36e6 | |||
| 7d06436d08 | |||
| 3bee380b18 | |||
| 58c70115f2 | |||
| 6be4081332 | |||
| 538e4a5d1f | |||
| 3e49572539 | |||
| 05c7152ad5 | |||
| 8d31fa2842 | |||
| 2abe39f178 | |||
| a6f47a9f92 | |||
| ac13287c78 | |||
| 305b92909e | |||
| 248667016a | |||
| 10b58aac73 | |||
| 0221fe8a34 | |||
| 1ff480e64d | |||
| fd121aae19 | |||
| 0deb19c53c | |||
| 7f3e389d92 | |||
| 87da2d4661 | |||
| f6075ae9ec | |||
| c424e84f4b | |||
| 3b4efe9636 | |||
| dfa27e78c6 | |||
| 9b57fe3eae | |||
| 8f60758a3c | |||
| 3a7ec4db32 | |||
| 679bc9f0d7 | |||
| 362eb38ff8 | |||
| 6243e992cf | |||
| e872414d57 | |||
| fcaf640bcb | |||
| f5237ceaf5 | |||
| 1503ec6629 | |||
| 0f744520ad | |||
| caf52cca20 | |||
| 1c4309c400 | |||
| 9725b921a5 | |||
| 38d2515dc5 | |||
| 13efd79f88 | |||
| 0c273d3571 | |||
| d22389b37a | |||
| f9b060e552 | |||
| 7d13f90e4a | |||
| f7a75a4fdc | |||
| b9fa97daad | |||
| 6f0f5b5e83 | |||
| 6fbd3184b1 | |||
| d5fee31ec6 | |||
| 2a93e04180 | |||
| b902ec9406 | |||
| e3ba570fb1 | |||
| fac65e5093 | |||
| eebc1f1d26 | |||
| 502ece5ba3 | |||
| 62967db201 | |||
| 4b7f863c71 | |||
| 55a6f17c91 | |||
| 8a32d7f73b | |||
| dfb6a705ea | |||
| 5246138398 | |||
| cc3e6a0822 | |||
| 8e68f58eff | |||
| 0a79a4d9fd | |||
| 48fb95bdc1 | |||
| bb4d3768b2 | |||
| cea3f0f341 | |||
| 35fc88c0ec | |||
| 312413aeb0 | |||
| 6ba060e116 | |||
| 88d5e1f50e | |||
| 644a8d3b4d | |||
| e80d135c15 | |||
| a40026f941 | |||
| fb25a36bf2 | |||
| 6f3f7c8e9a | |||
| c6c35d5639 | |||
| 63433cc58f | |||
| 940c0e03f7 | |||
| 445e498fbf | |||
| 09ad75f0cc | |||
| f8d9f9335e | |||
| cd31dafa97 | |||
| 6aa32701b8 | |||
| f84a622bfa | |||
| f60b7209f8 | |||
| 3b00a41fff | |||
| 119a7fab57 | |||
| 6d0a4a4d7b | |||
| 45404ecc71 | |||
| e5bfc2f6ad | |||
| c5be51053a | |||
| 4bfb5f51bf | |||
| d7a9facee9 | |||
| 260bc3721b | |||
| 3e0457de09 | |||
| ce6f6e0593 | |||
| f1efb700d2 | |||
| dd246296b9 | |||
| 22334d7c6c | |||
| c07698fcc8 | |||
| ce69272638 | |||
| 2b95d100b3 | |||
| b7706d4def | |||
| 845d46d7b3 | |||
| e4f8929f2c | |||
| c03402d525 | |||
| d8b18b17f6 | |||
| 5347266ed9 | |||
| 419c26adbf | |||
| 7727bdb51e | |||
| 37a58646fd | |||
| 0e747e3f15 | |||
| caf8a0a962 | |||
| 1b60c08dce | |||
| 1667514896 | |||
| 041cd03098 | |||
| 0c4998b091 | |||
| 7f25459169 | |||
| 91814ebfd9 | |||
| 7b3e8007c8 | |||
| 141761957d | |||
| b2ab2f606c | |||
| 40f0420e02 | |||
| 44e54ad555 | |||
| 69407ed8a5 | |||
| 13ee838f3c | |||
| ec33664734 | |||
| bfe8c4606d | |||
| a159bed3ba | |||
| 52f2065db4 | |||
| 0fd570a2c4 | |||
| 7df7f2740d | |||
| 458af34c67 | |||
| 21a3f5ca6f | |||
| bc7a797b71 | |||
| 9e888834e7 | |||
| 9709fad4d6 | |||
| 906e55f87b | |||
| 92812621be | |||
| 82b14a776f | |||
| 54a33225a2 | |||
| d7584de579 | |||
| a4c0d85bbb | |||
| 609615779c | |||
| b9364b5749 | |||
| 7cd7bef3ca | |||
| 80bd2d1ff0 | |||
| cbe84499fb | |||
| a8ee0a90e0 | |||
| c9de861216 | |||
| 0239202f09 | |||
| 2dd6208a80 | |||
| 37594fe8fa | |||
| e5c9b05ed6 | |||
| 9ba621b3ae | |||
| 9e20133ed9 | |||
| 9c11200666 | |||
| 3e0649a8d2 | |||
| b87bfe002a | |||
| f2e69594a7 | |||
| 7b39504050 | |||
| eff99e9287 | |||
| 6f8fcdab03 | |||
| c7a739d885 | |||
| 608962068a | |||
| e7615b4c08 | |||
| 5fa5ff8585 | |||
| 28a9338ab7 | |||
| 1d3747e9cd | |||
| c1c70ddace | |||
| 7ea690614e | |||
| 2909fd2505 | |||
| 7dd5450419 | |||
| e3a03e9d98 | |||
| dd39f94ca6 | |||
| 78232ff3a8 | |||
| aa02928620 | |||
| 52736ea0a3 | |||
| b7cc8e8100 | |||
| 520d4b4eab | |||
| 11a296acde | |||
| 8b1796147a | |||
| bf9d0e837e | |||
| a9301f5573 | |||
| e6e644e600 | |||
| 130975cebd | |||
| 5306d4b94a | |||
| 14a6c6b8ef | |||
| 2b31c8ad69 | |||
| ae02dcbe9a | |||
| e235199ff3 | |||
| 87ceee6c2d | |||
| 41e3e85159 | |||
| b570a4938c | |||
| 24f9916287 | |||
| cd22e55296 |
@@ -22,7 +22,7 @@ env:
|
||||
|
||||
jobs:
|
||||
build-cross:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
CCACHE_TEMPDIR: /tmp/.ccache-temp
|
||||
strategy:
|
||||
@@ -52,10 +52,10 @@ jobs:
|
||||
packages: "gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
|
||||
- name: "Cross-Mac x86_64"
|
||||
host: "x86_64-apple-darwin"
|
||||
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
|
||||
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python3-dev python3-setuptools-git"
|
||||
- name: "Cross-Mac aarch64"
|
||||
host: "aarch64-apple-darwin"
|
||||
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
|
||||
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python3-dev python3-setuptools-git"
|
||||
- name: "x86_64 Freebsd"
|
||||
host: "x86_64-unknown-freebsd"
|
||||
packages: "clang-8 gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
${{env.CCACHE_SETTINGS}}
|
||||
make depends target=${{ matrix.toolchain.host }} -j2
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin' || matrix.toolchain.host == 'aarch64-apple-darwin' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
|
||||
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin' || matrix.toolchain.host == 'aarch64-apple-darwin' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' || matrix.toolchain.host == 'aarch64-linux-gnu' }}
|
||||
with:
|
||||
name: ${{ matrix.toolchain.name }}
|
||||
path: |
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# Use Ubuntu 24.04 as base
|
||||
FROM ubuntu:24.04 AS builder
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install build dependencies including cross-compilers
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential cmake pkg-config git imagemagick libcap-dev librsvg2-bin libz-dev \
|
||||
g++-mingw-w64-x86-64 clang gcc-arm-none-eabi binutils-x86-64-linux-gnu libtiff-tools \
|
||||
g++-x86-64-linux-gnu gcc-x86-64-linux-gnu binutils-aarch64-linux-gnu \
|
||||
g++-aarch64-linux-gnu gcc-aarch64-linux-gnu crossbuild-essential-amd64 \
|
||||
libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev \
|
||||
libreadline-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev \
|
||||
libprotobuf-dev protobuf-compiler libudev-dev libboost-all-dev python3 ccache doxygen graphviz \
|
||||
ca-certificates curl zip libtool gperf automake autoconf \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Clone the develop branch
|
||||
WORKDIR /opt
|
||||
RUN git clone --recursive -b develop https://github.com/salvium/salvium.git
|
||||
WORKDIR /opt/salvium
|
||||
|
||||
# make the script runnable
|
||||
RUN chmod +x make_releases.sh
|
||||
|
||||
# Make sure the output folder exists
|
||||
RUN mkdir ~/releases
|
||||
|
||||
# Expose the releases directory for copying zip files to the host
|
||||
VOLUME ["~/releases"]
|
||||
|
||||
ENTRYPOINT ["/opt/salvium/make_releases.sh"]
|
||||
|
||||
|
||||
# To access the generated zip files on your host, run the container with:
|
||||
# docker run -v ~/releases:/root/releases <image>
|
||||
# This will copy the zip files to your host's ~/salvium-releases directory.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Salvium Zero v0.9.6
|
||||
# Salvium One v1.1.1
|
||||
|
||||
Copyright (c) 2023-2024, Salvium
|
||||
Copyright (c) 2023-2025, Salvium
|
||||
Portions Copyright (c) 2014-2023, The Monero Project
|
||||
Portions Copyright (c) 2012-2013 The Cryptonote developers.
|
||||
|
||||
@@ -47,7 +47,7 @@ As with many development projects, the repository on GitHub is considered to be
|
||||
|
||||
## Supporting the project
|
||||
|
||||
Salvium is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Go to [https://salvium.io/donate/](https://salvium.io/donate/) for more information.
|
||||
Salvium is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Go to [https://salvium.io/donate](https://salvium.io/donate) for more information.
|
||||
|
||||
## License
|
||||
|
||||
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
|
||||
|
||||
```bash
|
||||
cd salvium
|
||||
git checkout v0.9.6
|
||||
git checkout v1.1.1
|
||||
make
|
||||
```
|
||||
|
||||
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
|
||||
```bash
|
||||
git clone https://github.com/salvium/salvium
|
||||
cd salvium
|
||||
git checkout v0.9.6
|
||||
git checkout v1.1.1
|
||||
```
|
||||
|
||||
* Build:
|
||||
@@ -370,10 +370,10 @@ application.
|
||||
cd salvium
|
||||
```
|
||||
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.6'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v1.1.1'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.9.6
|
||||
git checkout v1.1.1
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
OSX_MIN_VERSION=10.13
|
||||
OSX_MIN_VERSION=11.0
|
||||
LD64_VERSION=609
|
||||
ifeq (aarch64, $(host_arch))
|
||||
CC_target=arm64-apple-$(host_os)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
mingw32_CFLAGS=-pipe -pthread
|
||||
mingw32_CFLAGS=-pipe
|
||||
mingw32_CXXFLAGS=$(mingw32_CFLAGS)
|
||||
mingw32_ARFLAGS=cr
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
package=boost
|
||||
$(package)_version=1.66.0
|
||||
package=boost
|
||||
$(package)_version=1.84.0
|
||||
$(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/
|
||||
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz
|
||||
$(package)_sha256_hash=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60
|
||||
$(package)_dependencies=libiconv
|
||||
$(package)_patches=fix_aroptions.patch fix_arm_arch.patch
|
||||
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.bz2
|
||||
$(package)_sha256_hash=cc4b893acf645c9d4b698e9a0f08ca8846aa5d6c68275c14c3e7949c24109454
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts_release=variant=release
|
||||
$(package)_config_opts_debug=variant=debug
|
||||
$(package)_config_opts=--layout=tagged --build-type=complete --user-config=user-config.jam
|
||||
$(package)_config_opts+=--layout=system --user-config=user-config.jam variant=release
|
||||
$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1
|
||||
$(package)_config_opts_linux=threadapi=pthread runtime-link=shared
|
||||
$(package)_config_opts_android=threadapi=pthread runtime-link=static target-os=android
|
||||
$(package)_config_opts_darwin=--toolset=darwin runtime-link=shared
|
||||
$(package)_config_opts_darwin=--toolset=darwin runtime-link=shared target-os=darwin
|
||||
$(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static
|
||||
$(package)_config_opts_x86_64_mingw32=address-model=64
|
||||
$(package)_config_opts_i686_mingw32=address-model=32
|
||||
@@ -22,20 +20,20 @@ $(package)_toolset_$(host_os)=gcc
|
||||
$(package)_archiver_$(host_os)=$($(package)_ar)
|
||||
$(package)_toolset_darwin=darwin
|
||||
$(package)_archiver_darwin=$($(package)_libtool)
|
||||
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
|
||||
$(package)_cxxflags=-std=c++11
|
||||
$(package)_cxxflags_linux=-fPIC
|
||||
$(package)_cxxflags_freebsd=-fPIC -DBOOST_ASIO_HAS_STD_STRING_VIEW=1
|
||||
$(package)_config_libraries_$(host_os)="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization"
|
||||
$(package)_config_libraries_mingw32="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale"
|
||||
$(package)_cxxflags=-std=c++17
|
||||
$(package)_cxxflags_linux+=-fPIC
|
||||
$(package)_cxxflags_freebsd+=-fPIC
|
||||
$(package)_cxxflags_darwin+=-ffile-prefix-map=$($(package)_extract_dir)=/usr
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/fix_aroptions.patch &&\
|
||||
patch -p1 < $($(package)_patch_dir)/fix_arm_arch.patch &&\
|
||||
echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : <cxxflags>\"$($(package)_cxxflags) $($(package)_cppflags)\" <linkflags>\"$($(package)_ldflags)\" <archiver>\"$(boost_archiver_$(host_os))\" <arflags>\"$($(package)_arflags)\" <striper>\"$(host_STRIP)\" <ranlib>\"$(host_RANLIB)\" <rc>\"$(host_WINDRES)\" : ;" > user-config.jam
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries)
|
||||
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries_$(host_os))
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
|
||||
@@ -5,17 +5,18 @@ $(package)_download_file=$($(package)_version).tar.gz
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=70a7189418c2086d20c299c5d59250cf5940782c778892ccc899c66516ed240e
|
||||
$(package)_build_subdir=cctools
|
||||
$(package)_dependencies=native_clang native_libtapi
|
||||
$(package)_patches=no-build-date.patch
|
||||
$(package)_dependencies=native_libtapi
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--target=$(host) --disable-lto-support --with-libtapi=$(host_prefix)
|
||||
$(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib
|
||||
$(package)_cc=$(host_prefix)/native/bin/clang
|
||||
$(package)_cxx=$(host_prefix)/native/bin/clang++
|
||||
$(package)_cc=$(clang_prog)
|
||||
$(package)_cxx=$(clangxx_prog)
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub cctools && \
|
||||
patch -p1 < $($(package)_patch_dir)/no-build-date.patch
|
||||
endef
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
package=native_clang
|
||||
$(package)_version=9.0.0
|
||||
$(package)_download_path=https://releases.llvm.org/$($(package)_version)
|
||||
$(package)_download_file=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
$(package)_file_name=clang-llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
$(package)_sha256_hash=a23b082b30c128c9831dbdd96edad26b43f56624d0ad0ea9edec506f5385038d
|
||||
#$(package)_version=9.0.0
|
||||
#$(package)_download_path=https://releases.llvm.org/$($(package)_version)
|
||||
#$(package)_download_file=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
#$(package)_file_name=clang-llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
#$(package)_sha256_hash=a23b082b30c128c9831dbdd96edad26b43f56624d0ad0ea9edec506f5385038d
|
||||
|
||||
$(package)_version=12.0.0
|
||||
$(package)_download_path=https://github.com/llvm/llvm-project/releases/download/llvmorg-$($(package)_version)
|
||||
$(package)_download_file=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-20.04.tar.xz
|
||||
$(package)_file_name=clang-llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-20.04.tar.xz
|
||||
$(package)_sha256_hash=a9ff205eb0b73ca7c86afc6432eed1c2d49133bd0d49e47b15be59bbf0dd292e
|
||||
|
||||
define $(package)_extract_cmds
|
||||
echo $($(package)_sha256_hash) $($(package)_source) | sha256sum -c &&\
|
||||
|
||||
@@ -4,30 +4,16 @@ $(package)_download_path=https://github.com/tpoechtrager/apple-libtapi/archive
|
||||
$(package)_download_file=$($(package)_version).tar.gz
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=62e419c12d1c9fad67cc1cd523132bc00db050998337c734c15bc8d73cc02b61
|
||||
$(package)_build_subdir=build
|
||||
$(package)_dependencies=native_clang
|
||||
$(package)_patches=no_embed_git_rev.patch
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 -i $($(package)_patch_dir)/no_embed_git_rev.patch
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
echo -n $(build_prefix) > INSTALLPREFIX; \
|
||||
CC=$(host_prefix)/native/bin/clang CXX=$(host_prefix)/native/bin/clang++ \
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$(build_prefix) \
|
||||
-DLLVM_INCLUDE_TESTS=OFF \
|
||||
-DCMAKE_BUILD_TYPE=RELEASE \
|
||||
-DTAPI_REPOSITORY_STRING="1100.0.11" \
|
||||
-DTAPI_FULL_VERSION="11.0.0" \
|
||||
-DCMAKE_CXX_FLAGS="-I $($(package)_extract_dir)/src/llvm/projects/clang/include -I $($(package)_build_dir)/projects/clang/include" \
|
||||
$($(package)_extract_dir)/src/llvm
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) clangBasic && $(MAKE) libtapi
|
||||
CC=$(clang_prog) CXX=$(clangxx_prog) INSTALLPREFIX=$($(package)_staging_prefix_dir) ./build.sh
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install-libtapi install-tapi-headers
|
||||
./install.sh
|
||||
endef
|
||||
|
||||
@@ -46,6 +46,7 @@ define $(package)_set_vars
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . && \
|
||||
cp $($(package)_patch_dir)/fallback.c ncurses
|
||||
endef
|
||||
|
||||
|
||||
@@ -1,38 +1,34 @@
|
||||
packages:=boost openssl zeromq libiconv expat unbound
|
||||
native_packages := native_protobuf
|
||||
packages := boost openssl zeromq unbound sodium protobuf
|
||||
|
||||
# ccache is useless in gitian builds
|
||||
ifneq ($(GITIAN),1)
|
||||
native_packages := native_ccache
|
||||
ifneq ($(host_os),android)
|
||||
packages += libusb
|
||||
endif
|
||||
|
||||
hardware_packages := hidapi protobuf libusb
|
||||
hardware_native_packages := native_protobuf
|
||||
|
||||
android_native_packages = android_ndk
|
||||
android_packages = ncurses readline sodium
|
||||
|
||||
darwin_native_packages = $(hardware_native_packages)
|
||||
darwin_packages = ncurses readline sodium $(hardware_packages)
|
||||
|
||||
# not really native...
|
||||
freebsd_native_packages = freebsd_base
|
||||
freebsd_packages = ncurses readline sodium
|
||||
|
||||
linux_packages = eudev ncurses readline sodium $(hardware_packages)
|
||||
linux_native_packages = $(hardware_native_packages)
|
||||
|
||||
ifeq ($(build_tests),ON)
|
||||
packages += gtest
|
||||
ifneq ($(host_os),freebsd)
|
||||
ifneq ($(host_os),android)
|
||||
packages += hidapi
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(host_arch),riscv64)
|
||||
linux_packages += unwind
|
||||
ifneq ($(host_os),mingw32)
|
||||
packages += ncurses readline
|
||||
endif
|
||||
|
||||
mingw32_packages = icu4c sodium $(hardware_packages)
|
||||
mingw32_native_packages = $(hardware_native_packages)
|
||||
mingw32_native_packages :=
|
||||
mingw32_packages = icu4c libiconv
|
||||
|
||||
linux_native_packages :=
|
||||
linux_packages := eudev
|
||||
|
||||
freebsd_native_packages := freebsd_base
|
||||
freebsd_packages :=
|
||||
|
||||
ifneq ($(build_os),darwin)
|
||||
darwin_native_packages += darwin_sdk native_clang native_cctools native_libtapi
|
||||
darwin_native_packages := darwin_sdk native_clang native_cctools native_libtapi
|
||||
endif
|
||||
darwin_packages :=
|
||||
|
||||
android_native_packages := android_ndk
|
||||
android_packages :=
|
||||
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
package=unbound
|
||||
$(package)_version=1.19.1
|
||||
$(package)_version=1.22.0
|
||||
$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=bc1d576f3dd846a0739adc41ffaa702404c6767d2b6082deb9f2f97cbb24a3a9
|
||||
$(package)_dependencies=openssl expat
|
||||
$(package)_patches=disable-glibc-reallocarray.patch
|
||||
|
||||
$(package)_sha256_hash=c5dd1bdef5d5685b2cedb749158dd152c52d44f65529a34ac15cd88d4b1b3d43
|
||||
$(package)_dependencies=openssl
|
||||
$(package)_patches=no-expat.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix)
|
||||
$(package)_config_opts+=--with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no
|
||||
$(package)_config_opts+=--with-libexpat=no --with-ssl=$(host_prefix) --with-libevent=no
|
||||
$(package)_config_opts+=--without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only
|
||||
$(package)_config_opts_linux=--with-pic
|
||||
$(package)_config_opts_w64=--enable-static-exe --sysconfdir=/etc --prefix=$(host_prefix) --target=$(host_prefix)
|
||||
$(package)_config_opts_x86_64_darwin=ac_cv_func_SHA384_Init=yes
|
||||
$(package)_build_opts_mingw32=LDFLAGS="$($(package)_ldflags) -lpthread"
|
||||
$(package)_cflags_mingw32+="-D_WIN32_WINNT=0x600"
|
||||
endef
|
||||
|
||||
# Remove blobs
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/disable-glibc-reallocarray.patch &&\
|
||||
autoconf
|
||||
patch -p1 < $($(package)_patch_dir)/no-expat.patch &&\
|
||||
rm configure~ doc/*.odp doc/*.pdf contrib/*.tar.gz contrib/*.tar.bz2 &&\
|
||||
rm -rf testdata dnscrypt/testdata
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
@@ -34,3 +34,7 @@ endef
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm -rf share
|
||||
endef
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
--- boost_1_64_0/tools/build/src/tools/darwin.jam.O 2017-04-17 03:22:26.000000000 +0100
|
||||
+++ boost_1_64_0/tools/build/src/tools/darwin.jam 2022-05-04 17:26:29.984464447 +0000
|
||||
@@ -505,7 +505,7 @@
|
||||
if $(instruction-set) {
|
||||
options = -arch$(_)$(instruction-set) ;
|
||||
} else {
|
||||
- options = -arch arm ;
|
||||
+# options = -arch arm ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
--- boost_1_64_0/tools/build/src/tools/gcc.jam.O 2017-04-17 03:22:26.000000000 +0100
|
||||
+++ boost_1_64_0/tools/build/src/tools/gcc.jam 2019-11-15 15:46:16.957937137 +0000
|
||||
@@ -243,6 +243,8 @@
|
||||
{
|
||||
ECHO notice: using gcc archiver :: $(condition) :: $(archiver[1]) ;
|
||||
}
|
||||
+ local arflags = [ feature.get-values <arflags> : $(options) ] ;
|
||||
+ toolset.flags gcc.archive .ARFLAGS $(condition) : $(arflags) ;
|
||||
|
||||
# - Ranlib.
|
||||
local ranlib = [ common.get-invocation-command gcc
|
||||
@@ -970,6 +972,7 @@
|
||||
# logic in intel-linux, but that is hardly worth the trouble as on Linux, 'ar'
|
||||
# is always available.
|
||||
.AR = ar ;
|
||||
+.ARFLAGS = rc ;
|
||||
.RANLIB = ranlib ;
|
||||
|
||||
toolset.flags gcc.archive AROPTIONS <archiveflags> ;
|
||||
@@ -1011,7 +1014,7 @@
|
||||
#
|
||||
actions piecemeal archive
|
||||
{
|
||||
- "$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)"
|
||||
+ "$(.AR)" $(AROPTIONS) $(.ARFLAGS) "$(<)" "$(>)"
|
||||
"$(.RANLIB)" "$(<)"
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 5c7da197..e2b25288 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -1702,6 +1702,9 @@ AC_LINK_IFELSE([AC_LANG_SOURCE(AC_INCLUDES_DEFAULT
|
||||
#ifndef _OPENBSD_SOURCE
|
||||
#define _OPENBSD_SOURCE 1
|
||||
#endif
|
||||
+#ifdef __linux__
|
||||
+# error reallocarray() is currently disabled on Linux to support glibc < 2.26
|
||||
+#endif
|
||||
#include <stdlib.h>
|
||||
int main(void) {
|
||||
void* p = reallocarray(NULL, 10, 100);
|
||||
@@ -0,0 +1,20 @@
|
||||
diff --git a/configure b/configure
|
||||
index a41e3e1e..7d6a58f0 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -22053,6 +22053,7 @@ else $as_nop
|
||||
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr"
|
||||
fi
|
||||
|
||||
+if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libexpat" >&5
|
||||
printf %s "checking for libexpat... " >&6; }
|
||||
found_libexpat="no"
|
||||
@@ -22090,6 +22091,7 @@ else $as_nop
|
||||
ac_have_decl=0
|
||||
fi
|
||||
printf "%s\n" "#define HAVE_DECL_XML_STOPPARSER $ac_have_decl" >>confdefs.h
|
||||
+fi
|
||||
|
||||
|
||||
# hiredis (redis C client for cachedb)
|
||||
@@ -91,7 +91,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
SET(BREW OFF)
|
||||
SET(PORT OFF)
|
||||
SET(CMAKE_OSX_SYSROOT "@prefix@/native/SDK/")
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
|
||||
SET(CMAKE_CXX_STANDARD 17)
|
||||
SET(LLVM_ENABLE_PIC OFF)
|
||||
SET(LLVM_ENABLE_PIE OFF)
|
||||
|
||||
Vendored
+1
-1
Submodule external/mx25519 updated: 42f36ede5f...e808a6406b
@@ -0,0 +1,5 @@
|
||||
48417220800f174a3613881a56131d25c49d344228fca124c8331e0b58a8ff06 salvium-v1.0.7-ubuntu22.04-linux-x86_64.zip
|
||||
52226551a9e1842df46cf068292cfa3c1e05328e0695cf6723365d4401af19a6 salvium-v1.0.7-ubuntu22.04-linux-aarch64.zip
|
||||
b40c3765479c9d5712e766ddd01314b63e5080472b7639d34388e6b74b36142e salvium-v1.0.7-macos-x86_64.zip
|
||||
60b05548f69040fe901e336e8fc4189a1028a8d7ded09bad555b3c854a0e8d6e salvium-v1.0.7-macos-aarch64.zip
|
||||
b2c3e0bb8254ad1f62a78d6670c6e5adba1e42bb823919faad1cbf5796d53910 salvium-v1.0.7-win64.zip
|
||||
@@ -0,0 +1,5 @@
|
||||
e032e42ebac862bf90d71f0a231d9f3ddb5583e321ec153ee05144d87629980b salvium-v1.1.0-macos-aarch64.zip
|
||||
0f31f09cf7be38b50a35510172bc94b7a4fb07c7107c79c4f055754c282c99f5 salvium-v1.1.0-macos-x86_64.zip
|
||||
4424fd93391daab7eee47c54ab7aad7810a16f4c866209d41ba016d984605ffb salvium-v1.1.0-ubuntu22.04-linux-aarch64.zip
|
||||
d1a5138f892189dfccc1d51d72ce24147fe6f1a2a5d465d350651426a71282a4 salvium-v1.1.0-ubuntu22.04-linux-x86_64.zip
|
||||
bb9c9175726b82e061a6a332a27a6845805be4779928df3abbbd5c0f54691c9a salvium-v1.1.0-win64.zip
|
||||
@@ -0,0 +1,5 @@
|
||||
d0a8b0515ae2ee79849cbc17b0639bb7859e30efcd50e5b058540874cd0919ce salvium-v1.1.0-rc4-ubuntu22.04-linux-x86_64.zip
|
||||
6528b8b23f09c574fc9383b48b88e87f99609ff5ce1b727872b5554505a69d77 salvium-v1.1.0-rc4-ubuntu22.04-linux-aarch64.zip
|
||||
00ca183c47f852b8b30e4b87ce3b3536a0e97866e6027bf25d389b4a1bc9c471 salvium-v1.1.0-rc4-macos-x86_64.zip
|
||||
50480b1043e9b5901576ab45f926b0b51a5d21237c6da549603ad1f13819e6ed salvium-v1.1.0-rc4-macos-aarch64.zip
|
||||
adf96eee17e16f318fc047721acb5bfa8ae7ed1c0ff8d022da8ab5df64d8ce3f salvium-v1.1.0-rc4-win64.zip
|
||||
@@ -0,0 +1,5 @@
|
||||
23a03277e922c3f41ba6ddb0efc7581c3287d9f3faa2ddd19cc2d018a6797701 salvium-v1.1.0-rc5-ubuntu22.04-linux-x86_64.zip
|
||||
94409b190eae890792b2d04cfffe148828dc23d658cd54a8d7802b12a9f274a4 salvium-v1.1.0-rc5-ubuntu22.04-linux-aarch64.zip
|
||||
76cc02603cb21cd0729f0e5c9a39bb32310428b15580458ec8d74dcba39c9319 salvium-v1.1.0-rc5-macos-x86_64.zip
|
||||
dc477718bfb370ecbafebf3e1736df5978200302f13542374f1b1fd43e07ab45 salvium-v1.1.0-rc5-macos-aarch64.zip
|
||||
0e9b81eeaa32a4709a1cbd4c198721455a3c8cc86c1f1915cfc74af7885f8fee salvium-v1.1.0-rc5-win64.zip
|
||||
@@ -0,0 +1,5 @@
|
||||
b712adec8fa6bbcbe461b0748649e4c9e4fb61934fc1adb064779afed28c0758 salvium-v1.1.0-rc6-macos-aarch64.zip
|
||||
8635955ff784f936a8b8de5be267e5dcdc0b55dfbf0b6f65ba24d098d8b8ab00 salvium-v1.1.0-rc6-macos-x86_64.zip
|
||||
79b65ba9a074aeba87f03d83a07c3a6c51815d376049b3136a38c1a33260bfac salvium-v1.1.0-rc6-ubuntu22.04-linux-aarch64.zip
|
||||
9031763ad60d1c8c572c76c5cb51a96b1680b9708c287264388f3d411bda464f salvium-v1.1.0-rc6-ubuntu22.04-linux-x86_64.zip
|
||||
e3a8e53e092041ed9ed32c98d5d0ecf548f42232402748f862371ba21e1f1f9f salvium-v1.1.0-rc6-win64.zip
|
||||
@@ -238,7 +238,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair
|
||||
LOG_PRINT_L1("Failed to get output unlock time, aborting transaction addition");
|
||||
throw std::runtime_error("Unexpected error getting output unlock_time, aborting");
|
||||
}
|
||||
if (miner_tx && tx.version == 2)
|
||||
if (miner_tx && tx.version >= 2)
|
||||
{
|
||||
cryptonote::tx_out vout = tx.vout[i];
|
||||
// TODO: avoid multiple expensive zeroCommitVartime call here + get_outs_by_last_locked_block + ver_non_input_consensus
|
||||
@@ -294,7 +294,22 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
time1 = epee::misc_utils::get_tick_count();
|
||||
|
||||
uint64_t num_rct_outs = 0;
|
||||
oracle::asset_type_counts num_rct_outs_by_asset_type;
|
||||
oracle::asset_type_counts_v2 num_rct_outs_by_asset_type;
|
||||
|
||||
// add newly created tokens
|
||||
for (const std::pair<transaction, blobdata>& tx : txs)
|
||||
{
|
||||
if (tx.first.type == cryptonote::transaction_type::CREATE_TOKEN)
|
||||
{
|
||||
uint32_t asset_type_id = cryptonote::asset_id_from_type("sal" + tx.first.token_metadata.asset_type);
|
||||
if (!num_rct_outs_by_asset_type.add_asset_type(asset_type_id))
|
||||
throw std::runtime_error("Failed to add asset_type 'sal" + tx.first.token_metadata.asset_type + "'");
|
||||
}
|
||||
|
||||
if (!is_tx_paid_for(tx.first))
|
||||
throw std::runtime_error("TX is not paid for");
|
||||
}
|
||||
|
||||
blobdata miner_bd = tx_to_blob(blk.miner_tx);
|
||||
add_transaction(blk_hash, std::make_pair(blk.miner_tx, blobdata_ref(miner_bd)));
|
||||
blobdata protocol_bd = tx_to_blob(blk.protocol_tx);
|
||||
@@ -309,12 +324,14 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
std::string asset_type;
|
||||
if (!get_output_asset_type(vout, asset_type))
|
||||
throw std::runtime_error("Failed to get output asset type");
|
||||
num_rct_outs_by_asset_type.add(asset_type, 1);
|
||||
uint32_t asset_type_id = cryptonote::asset_id_from_type(asset_type);
|
||||
num_rct_outs_by_asset_type.add_asset_type(asset_type_id);
|
||||
num_rct_outs_by_asset_type.add(asset_type_id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, int64_t> slippage_counts;
|
||||
uint64_t audit_total = 0, yield_total = 0;
|
||||
uint64_t audit_total = 0, token_total = 0, yield_total = 0;
|
||||
if (blk.protocol_tx.version >= 2)
|
||||
{
|
||||
num_rct_outs += blk.protocol_tx.vout.size();
|
||||
@@ -326,10 +343,12 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
std::string asset_type;
|
||||
if (!get_output_asset_type(vout, asset_type))
|
||||
throw std::runtime_error("Failed to get output asset type");
|
||||
uint32_t asset_type_id = cryptonote::asset_id_from_type(asset_type);
|
||||
|
||||
// Update the RCT outs for the asset_type
|
||||
num_rct_outs_by_asset_type.add_asset_type(asset_type_id);
|
||||
num_rct_outs_by_asset_type.add(asset_type_id, 1);
|
||||
|
||||
// Update the RCT outs
|
||||
num_rct_outs_by_asset_type.add(asset_type, 1);
|
||||
|
||||
// Update the amount tallies by DEDUCTING the minted amount
|
||||
if (slippage_counts.count(asset_type) == 0)
|
||||
slippage_counts[asset_type] = 0;
|
||||
@@ -350,7 +369,9 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
throw std::runtime_error("Failed to get output asset type");
|
||||
if (vout.amount == 0) {
|
||||
++num_rct_outs;
|
||||
num_rct_outs_by_asset_type.add(asset_type, 1);
|
||||
uint32_t asset_type_id = cryptonote::asset_id_from_type(asset_type);
|
||||
num_rct_outs_by_asset_type.add_asset_type(asset_type_id);
|
||||
num_rct_outs_by_asset_type.add(asset_type_id, 1);
|
||||
}
|
||||
|
||||
// Is this a CONVERT TX?
|
||||
@@ -367,6 +388,16 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
audit_total += tx.first.amount_burnt;
|
||||
}
|
||||
|
||||
// Is this an create_token TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
token_total += tx.first.amount_burnt;
|
||||
/*
|
||||
uint32_t asset_type_id = cryptonote::asset_id_from_type(tx.first.token_metadata.asset_type);
|
||||
if (!num_rct_outs_by_asset_type.add_asset_type(asset_type_id))
|
||||
throw std::runtime_error("Failed to add asset_type '" + tx.first.token_metadata.asset_type + "' to RCT outputs");
|
||||
*/
|
||||
}
|
||||
|
||||
// Is this a STAKE TX?
|
||||
if (tx.first.type == cryptonote::transaction_type::STAKE) {
|
||||
yield_total += tx.first.amount_burnt;
|
||||
@@ -420,7 +451,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
|
||||
|
||||
// call out to subclass implementation to add the block & metadata
|
||||
time1 = epee::misc_utils::get_tick_count();
|
||||
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, num_rct_outs_by_asset_type, blk_hash, slippage_total, yield_total, audit_total, nettype, ybi, abi);
|
||||
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, num_rct_outs_by_asset_type, blk_hash, slippage_total, yield_total, audit_total, token_total, nettype, ybi, abi);
|
||||
TIME_MEASURE_FINISH(time1);
|
||||
time_add_block1 += time1;
|
||||
|
||||
|
||||
@@ -207,6 +207,29 @@ typedef struct yield_tx_info {
|
||||
crypto::public_key return_pubkey;
|
||||
} yield_tx_info;
|
||||
|
||||
typedef struct yield_tx_info_carrot {
|
||||
uint64_t block_height;
|
||||
uint8_t version;
|
||||
crypto::hash tx_hash;
|
||||
uint64_t locked_coins;
|
||||
crypto::public_key return_address;
|
||||
crypto::public_key return_pubkey;
|
||||
carrot::view_tag_t return_view_tag;
|
||||
carrot::encrypted_janus_anchor_t return_anchor_enc;
|
||||
} yield_tx_info_carrot;
|
||||
|
||||
typedef struct token_tx_info_carrot {
|
||||
uint64_t block_height;
|
||||
uint8_t version;
|
||||
crypto::hash tx_hash;
|
||||
uint64_t locked_coins;
|
||||
crypto::public_key return_address;
|
||||
crypto::public_key return_pubkey;
|
||||
carrot::view_tag_t return_view_tag;
|
||||
carrot::encrypted_janus_anchor_t return_anchor_enc;
|
||||
uint32_t asset_type_id;
|
||||
} token_tx_info_carrot;
|
||||
|
||||
#define DBF_SAFE 1
|
||||
#define DBF_FAST 2
|
||||
#define DBF_FASTEST 4
|
||||
@@ -426,11 +449,12 @@ private:
|
||||
const difficulty_type& cumulative_difficulty,
|
||||
const uint64_t& coins_generated,
|
||||
uint64_t num_rct_outs,
|
||||
oracle::asset_type_counts& cum_rct_by_asset_type,
|
||||
oracle::asset_type_counts_v2& cum_rct_by_asset_type,
|
||||
const crypto::hash& blk_hash,
|
||||
uint64_t slippage_total,
|
||||
uint64_t yield_total,
|
||||
uint64_t audit_total,
|
||||
uint64_t token_total,
|
||||
const cryptonote::network_type nettype,
|
||||
cryptonote::yield_block_info& ybi,
|
||||
cryptonote::audit_block_info& abi
|
||||
@@ -1201,6 +1225,20 @@ public:
|
||||
virtual std::map<std::string, uint64_t> get_circulating_supply() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @brief fetch the tokens from the blockchain
|
||||
*
|
||||
* @return the current token values
|
||||
*/
|
||||
virtual std::map<std::string, cryptonote::token_metadata_t> get_tokens() const = 0;
|
||||
|
||||
/**
|
||||
* @brief determine if a TX has been paid for
|
||||
*
|
||||
* @return the current token values
|
||||
*/
|
||||
virtual bool is_tx_paid_for(const cryptonote::transaction& tx) const = 0;
|
||||
|
||||
/**
|
||||
* <!--
|
||||
* TODO: Rewrite (if necessary) such that all calls to remove_* are
|
||||
@@ -1924,6 +1962,10 @@ public:
|
||||
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const = 0;
|
||||
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const = 0;
|
||||
|
||||
virtual int get_carrot_yield_tx_info(const uint64_t height, std::vector<yield_tx_info_carrot>& yti_container) const = 0;
|
||||
|
||||
virtual int get_token_tx_info(const uint64_t height, std::vector<token_tx_info_carrot>& tti_container) const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* @brief set whether or not to automatically remove logs
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -80,7 +80,16 @@ typedef struct mdb_txn_cursors
|
||||
MDB_cursor *m_txc_yield_blocks;
|
||||
MDB_cursor *m_txc_audit_txs;
|
||||
MDB_cursor *m_txc_audit_blocks;
|
||||
MDB_cursor *m_txc_carrot_yield_txs;
|
||||
|
||||
MDB_cursor *m_txc_token_txs;
|
||||
MDB_cursor *m_txc_tokens;
|
||||
MDB_cursor *m_txc_asset_type_counts;
|
||||
|
||||
MDB_cursor *m_txc_rct_count_info;
|
||||
|
||||
MDB_cursor *m_txc_rollup_tx_info;
|
||||
|
||||
} mdb_txn_cursors;
|
||||
|
||||
#define m_cur_blocks m_cursors->m_txc_blocks
|
||||
@@ -108,6 +117,15 @@ typedef struct mdb_txn_cursors
|
||||
#define m_cur_yield_blocks m_cursors->m_txc_yield_blocks
|
||||
#define m_cur_audit_txs m_cursors->m_txc_audit_txs
|
||||
#define m_cur_audit_blocks m_cursors->m_txc_audit_blocks
|
||||
#define m_cur_carrot_yield_txs m_cursors->m_txc_carrot_yield_txs
|
||||
|
||||
#define m_cur_token_txs m_cursors->m_txc_token_txs
|
||||
#define m_cur_tokens m_cursors->m_txc_tokens
|
||||
#define m_cur_asset_type_counts m_cursors->m_txc_asset_type_counts
|
||||
|
||||
#define m_cur_rct_count_info m_cursors->m_txc_rct_count_info
|
||||
|
||||
#define m_cur_rollup_tx_info m_cursors->m_txc_rollup_tx_info
|
||||
|
||||
typedef struct mdb_rflags
|
||||
{
|
||||
@@ -137,6 +155,16 @@ typedef struct mdb_rflags
|
||||
bool m_rf_yield_blocks;
|
||||
bool m_rf_audit_txs;
|
||||
bool m_rf_audit_blocks;
|
||||
bool m_rf_carrot_yield_txs;
|
||||
|
||||
bool m_rf_token_txs;
|
||||
bool m_rf_tokens;
|
||||
bool m_rf_asset_type_counts;
|
||||
|
||||
bool m_rf_rct_count_info;
|
||||
|
||||
bool m_rf_rollup_tx_info;
|
||||
|
||||
} mdb_rflags;
|
||||
|
||||
typedef struct mdb_threadinfo
|
||||
@@ -239,6 +267,8 @@ public:
|
||||
|
||||
virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const;
|
||||
|
||||
virtual std::pair<std::vector<uint64_t>, uint64_t> get_block_cumulative_rct_outputs_old(const std::vector<uint64_t> &heights, const std::string asset_type) const;
|
||||
|
||||
virtual std::pair<std::vector<uint64_t>, uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights, const std::string asset_type) const;
|
||||
|
||||
virtual uint64_t get_block_timestamp(const uint64_t& height) const;
|
||||
@@ -274,6 +304,10 @@ public:
|
||||
virtual uint64_t height() const;
|
||||
|
||||
virtual std::map<std::string, uint64_t> get_circulating_supply() const;
|
||||
|
||||
virtual std::map<std::string, cryptonote::token_metadata_t> get_tokens() const;
|
||||
|
||||
virtual bool is_tx_paid_for(const cryptonote::transaction& tx) const;
|
||||
|
||||
virtual bool tx_exists(const crypto::hash& h) const;
|
||||
virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const;
|
||||
@@ -403,11 +437,12 @@ private:
|
||||
const difficulty_type& cumulative_difficulty,
|
||||
const uint64_t& coins_generated,
|
||||
uint64_t num_rct_outs,
|
||||
oracle::asset_type_counts& cum_rct_by_asset_type,
|
||||
oracle::asset_type_counts_v2& cum_rct_by_asset_type,
|
||||
const crypto::hash& blk_hash,
|
||||
uint64_t slippage_total,
|
||||
uint64_t yield_total,
|
||||
uint64_t audit_total,
|
||||
uint64_t token_total,
|
||||
const cryptonote::network_type nettype,
|
||||
cryptonote::yield_block_info& ybi,
|
||||
cryptonote::audit_block_info& abi
|
||||
@@ -474,6 +509,9 @@ private:
|
||||
|
||||
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const;
|
||||
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const;
|
||||
virtual int get_carrot_yield_tx_info(const uint64_t height, std::vector<yield_tx_info_carrot>& yti_container) const;
|
||||
|
||||
virtual int get_token_tx_info(const uint64_t height, std::vector<token_tx_info_carrot>& tti_container) const;
|
||||
|
||||
private:
|
||||
MDB_env* m_env;
|
||||
@@ -511,10 +549,20 @@ private:
|
||||
|
||||
MDB_dbi m_yield_txs;
|
||||
MDB_dbi m_yield_blocks;
|
||||
|
||||
|
||||
MDB_dbi m_audit_txs;
|
||||
MDB_dbi m_audit_blocks;
|
||||
|
||||
MDB_dbi m_carrot_yield_txs;
|
||||
|
||||
MDB_dbi m_token_txs;
|
||||
MDB_dbi m_tokens;
|
||||
MDB_dbi m_asset_type_counts;
|
||||
|
||||
MDB_dbi m_rct_count_info;
|
||||
|
||||
MDB_dbi m_rollup_tx_info;
|
||||
|
||||
mutable uint64_t m_cum_size; // used in batch size estimation
|
||||
mutable unsigned int m_cum_count;
|
||||
std::string m_folder;
|
||||
|
||||
@@ -145,6 +145,7 @@ public:
|
||||
|
||||
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const override { return 0; }
|
||||
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const override { return 0; }
|
||||
virtual int get_carrot_yield_tx_info(const uint64_t height, std::vector<yield_tx_info_carrot>& yti_container) const override { return 0; }
|
||||
|
||||
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const override { return ""; }
|
||||
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata_ref*)>, bool include_blob = false, relay_category category = relay_category::broadcasted) const override { return false; }
|
||||
@@ -155,15 +156,20 @@ public:
|
||||
const difficulty_type& cumulative_difficulty,
|
||||
const uint64_t& coins_generated,
|
||||
uint64_t num_rct_outs,
|
||||
oracle::asset_type_counts& cum_rct_by_asset_type,
|
||||
oracle::asset_type_counts_v2& cum_rct_by_asset_type,
|
||||
const crypto::hash& blk_hash,
|
||||
uint64_t slippage_total,
|
||||
uint64_t yield_total,
|
||||
uint64_t audit_total,
|
||||
uint64_t token_total,
|
||||
const cryptonote::network_type nettype,
|
||||
cryptonote::yield_block_info& ybi,
|
||||
cryptonote::audit_block_info& abi
|
||||
) override { }
|
||||
|
||||
virtual std::map<std::string, cryptonote::token_metadata_t> get_tokens() const override { return {}; }
|
||||
virtual bool is_tx_paid_for(const cryptonote::transaction& tx) const override { return true; }
|
||||
virtual int get_token_tx_info(const uint64_t height, std::vector<token_tx_info_carrot>& tti_container) const override { return 0; }
|
||||
virtual cryptonote::block get_block_from_height(const uint64_t& height) const override { return cryptonote::block(); }
|
||||
virtual void set_hard_fork_version(uint64_t height, uint8_t version) override {}
|
||||
virtual uint8_t get_hard_fork_version(uint64_t height) const override { return 0; }
|
||||
|
||||
@@ -214,11 +214,9 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
|
||||
#define MAX_RINGS 0xffffffff
|
||||
|
||||
struct tm prevtm = {0}, currtm;
|
||||
uint64_t prevsz = 0, currsz = 0;
|
||||
uint64_t prevtxs = 0, currtxs = 0;
|
||||
uint64_t currblks = 0;
|
||||
uint32_t txhr[24] = {0};
|
||||
unsigned int i;
|
||||
// uint64_t currsz = 0;
|
||||
// uint64_t currtxs = 0;
|
||||
// uint64_t currblks = 0;
|
||||
|
||||
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(net_type).AUDIT_HARD_FORKS;
|
||||
|
||||
@@ -246,9 +244,7 @@ plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, ''
|
||||
prevtm = currtm;
|
||||
}
|
||||
skip:
|
||||
currsz += bd.size();
|
||||
uint64_t coinbase_amount;
|
||||
uint64_t tx_fee_amount = 0;
|
||||
// currsz += bd.size();
|
||||
std::set<std::string> used_assets, miner_tx_assets, protocol_tx_assets;
|
||||
std::map<size_t, std::vector<std::string>> used_tx_versions;
|
||||
used_assets.insert("SAL");
|
||||
@@ -325,10 +321,11 @@ skip:
|
||||
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX detected" << delimiter << std::endl;
|
||||
continue;
|
||||
}
|
||||
currsz += bd.size();
|
||||
if (db->get_prunable_tx_blob(tx_id, bd))
|
||||
currsz += bd.size();
|
||||
currtxs++;
|
||||
// currsz += bd.size();
|
||||
// if (db->get_prunable_tx_blob(tx_id, bd))
|
||||
// currsz += bd.size();
|
||||
// currtxs++;
|
||||
db->get_prunable_tx_blob(tx_id, bd);
|
||||
|
||||
if (tx.type != cryptonote::transaction_type::TRANSFER &&
|
||||
tx.type != cryptonote::transaction_type::BURN &&
|
||||
@@ -374,7 +371,7 @@ skip:
|
||||
}
|
||||
}
|
||||
|
||||
currblks++;
|
||||
// currblks++;
|
||||
|
||||
if (stop_requested)
|
||||
break;
|
||||
|
||||
@@ -211,8 +211,15 @@ int main(int argc, char* argv[])
|
||||
throw std::runtime_error("Failed to initialize a database");
|
||||
}
|
||||
|
||||
const std::string filename = (boost::filesystem::path(opt_data_dir) / db->get_db_name()).string();
|
||||
LOG_PRINT_L0("Loading blockchain from folder " << filename << " ...");
|
||||
boost::filesystem::path folder(opt_data_dir);
|
||||
if (opt_stagenet) {
|
||||
folder /= std::to_string(STAGENET_VERSION);
|
||||
} else if (opt_testnet) {
|
||||
folder /= std::to_string(TESTNET_VERSION);
|
||||
}
|
||||
folder /= db->get_db_name();
|
||||
LOG_PRINT_L0("Loading blockchain from folder " << folder << " ...");
|
||||
const std::string filename = folder.string();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
Binary file not shown.
@@ -29,6 +29,7 @@
|
||||
set(carrot_core_sources
|
||||
account_secrets.cpp
|
||||
address_utils.cpp
|
||||
account.cpp
|
||||
carrot_enote_types.cpp
|
||||
core_types.cpp
|
||||
destination.cpp
|
||||
|
||||
@@ -0,0 +1,480 @@
|
||||
// Copyright (c) 2014-2022, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "account.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/generators.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "crypto/keccak.h"
|
||||
}
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "ringct/rctOps.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "carrot_impl_account"
|
||||
|
||||
using namespace std;
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345)
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
CarrotDestinationV1 carrot_and_legacy_account::cryptonote_address(const payment_id_t payment_id,
|
||||
const AddressDeriveType derive_type) const
|
||||
{
|
||||
CarrotDestinationV1 addr;
|
||||
switch (resolve_derive_type(derive_type))
|
||||
{
|
||||
case AddressDeriveType::Carrot:
|
||||
make_carrot_integrated_address_v1(get_keys().m_carrot_main_address.m_spend_public_key,
|
||||
get_keys().m_carrot_main_address.m_view_public_key,
|
||||
payment_id,
|
||||
addr);
|
||||
break;
|
||||
case AddressDeriveType::PreCarrot:
|
||||
make_carrot_integrated_address_v1(get_keys().m_account_address.m_spend_public_key,
|
||||
get_keys().m_account_address.m_view_public_key,
|
||||
payment_id,
|
||||
addr);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("address derive type not recognized");
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
CarrotDestinationV1 carrot_and_legacy_account::subaddress(const subaddress_index_extended &subaddress_index) const
|
||||
{
|
||||
if (!subaddress_index.index.is_subaddress())
|
||||
return cryptonote_address(null_payment_id, subaddress_index.derive_type);
|
||||
|
||||
const cryptonote::account_keys &keys = get_keys();
|
||||
|
||||
CarrotDestinationV1 addr;
|
||||
cryptonote::account_public_address cnaddr;
|
||||
switch (resolve_derive_type(subaddress_index.derive_type))
|
||||
{
|
||||
case AddressDeriveType::Carrot:
|
||||
make_carrot_subaddress_v1(keys.m_carrot_account_address.m_spend_public_key,
|
||||
keys.m_carrot_account_address.m_view_public_key,
|
||||
s_generate_address_dev,
|
||||
subaddress_index.index.major,
|
||||
subaddress_index.index.minor,
|
||||
addr);
|
||||
break;
|
||||
case AddressDeriveType::PreCarrot:
|
||||
cnaddr =
|
||||
keys.m_device->get_subaddress(keys, {subaddress_index.index.major, subaddress_index.index.minor});
|
||||
addr = CarrotDestinationV1{
|
||||
.address_spend_pubkey = cnaddr.m_spend_public_key,
|
||||
.address_view_pubkey = cnaddr.m_view_public_key,
|
||||
.is_subaddress = true,
|
||||
.payment_id = null_payment_id
|
||||
};
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("address derive type not recognized");
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> carrot_and_legacy_account::get_subaddress_map_cn() const
|
||||
{
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> res;
|
||||
for (const auto &p : subaddress_map)
|
||||
res.emplace(p.first, cryptonote::subaddress_index{p.second.index.major, p.second.index.minor});
|
||||
CHECK_AND_ASSERT_THROW_MES(!res.empty(),
|
||||
"carrot_and_legacy_account::get_subaddress_map: subaddress map does not contain subaddresses");
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
const std::unordered_map<crypto::public_key, subaddress_index_extended>& carrot_and_legacy_account::get_subaddress_map_ref() const {
|
||||
return subaddress_map;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
const std::unordered_map<crypto::public_key, return_output_info_t>&
|
||||
carrot_and_legacy_account::get_return_output_map_ref() const {
|
||||
return return_output_map;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::opening_for_subaddress(const subaddress_index_extended &subaddress_index,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
crypto::secret_key &address_privkey_t_out,
|
||||
crypto::public_key &address_spend_pubkey_out) const
|
||||
{
|
||||
const bool is_subaddress = subaddress_index.index.is_subaddress();
|
||||
const uint32_t major_index = subaddress_index.index.major;
|
||||
const uint32_t minor_index = subaddress_index.index.minor;
|
||||
|
||||
const cryptonote::account_keys &keys = get_keys();
|
||||
|
||||
crypto::secret_key address_index_generator;
|
||||
crypto::secret_key subaddress_scalar;
|
||||
crypto::secret_key subaddress_extension;
|
||||
|
||||
switch (resolve_derive_type(subaddress_index.derive_type))
|
||||
{
|
||||
case AddressDeriveType::Carrot:
|
||||
// s^j_gen = H_32[s_ga](j_major, j_minor)
|
||||
make_carrot_index_extension_generator(keys.s_generate_address, major_index, minor_index, address_index_generator);
|
||||
|
||||
if (is_subaddress)
|
||||
{
|
||||
// k^j_subscal = H_n(K_s, j_major, j_minor, s^j_gen)
|
||||
make_carrot_subaddress_scalar(keys.m_carrot_account_address.m_spend_public_key, address_index_generator, major_index, minor_index, subaddress_scalar);
|
||||
}
|
||||
else
|
||||
{
|
||||
// k^j_subscal = 1
|
||||
sc_1(to_bytes(subaddress_scalar));
|
||||
}
|
||||
|
||||
// k^g_a = k_gi * k^j_subscal
|
||||
sc_mul(to_bytes(address_privkey_g_out), to_bytes(keys.k_generate_image), to_bytes(subaddress_scalar));
|
||||
|
||||
// k^t_a = k_ps * k^j_subscal
|
||||
sc_mul(to_bytes(address_privkey_t_out), to_bytes(keys.k_prove_spend), to_bytes(subaddress_scalar));
|
||||
break;
|
||||
case AddressDeriveType::PreCarrot:
|
||||
// m = Hn(k_v || j_major || j_minor) if subaddress else 0
|
||||
subaddress_extension = is_subaddress
|
||||
? keys.get_device().get_subaddress_secret_key(keys.m_view_secret_key, {major_index, minor_index})
|
||||
: crypto::null_skey;
|
||||
|
||||
// k^g_a = k_s + m
|
||||
sc_add(to_bytes(address_privkey_g_out), to_bytes(keys.m_spend_secret_key), to_bytes(subaddress_extension));
|
||||
|
||||
// k^t_a = 0
|
||||
memset(address_privkey_t_out.data, 0, sizeof(address_privkey_t_out));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("address derive type not recognized");
|
||||
}
|
||||
|
||||
// perform sanity check
|
||||
const CarrotDestinationV1 addr = subaddress(subaddress_index);
|
||||
rct::key recomputed_address_spend_pubkey;
|
||||
rct::addKeys2(recomputed_address_spend_pubkey,
|
||||
rct::sk2rct(address_privkey_g_out),
|
||||
rct::sk2rct(address_privkey_t_out),
|
||||
rct::pk2rct(crypto::get_T()));
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::rct2pk(recomputed_address_spend_pubkey) == addr.address_spend_pubkey,
|
||||
"carrot and legacy account: opening for subaddress: failed sanity check");
|
||||
address_spend_pubkey_out = addr.address_spend_pubkey;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
bool carrot_and_legacy_account::try_searching_for_opening_for_subaddress(const crypto::public_key &address_spend_pubkey,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
crypto::secret_key &address_privkey_t_out) const
|
||||
{
|
||||
const auto it = subaddress_map.find(address_spend_pubkey);
|
||||
if (it == subaddress_map.cend())
|
||||
return false;
|
||||
|
||||
crypto::public_key recomputed_address_spend_pubkey;
|
||||
opening_for_subaddress(it->second,
|
||||
address_privkey_g_out,
|
||||
address_privkey_t_out,
|
||||
recomputed_address_spend_pubkey);
|
||||
|
||||
return address_spend_pubkey == recomputed_address_spend_pubkey;
|
||||
}
|
||||
bool carrot_and_legacy_account::try_searching_for_opening_for_onetime_address(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
crypto::secret_key &x_out,
|
||||
crypto::secret_key &y_out) const
|
||||
{
|
||||
// k^{j,g}_addr, k^{j,t}_addr
|
||||
crypto::secret_key address_privkey_g;
|
||||
crypto::secret_key address_privkey_t;
|
||||
if (!try_searching_for_opening_for_subaddress(address_spend_pubkey,
|
||||
address_privkey_g,
|
||||
address_privkey_t))
|
||||
return false;
|
||||
|
||||
// x = k^{j,g}_addr + k^g_o
|
||||
sc_add(to_bytes(x_out), to_bytes(address_privkey_g), to_bytes(sender_extension_g));
|
||||
|
||||
// y = k^{j,t}_addr + k^t_o
|
||||
sc_add(to_bytes(y_out), to_bytes(address_privkey_t), to_bytes(sender_extension_t));
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
bool carrot_and_legacy_account::can_open_fcmp_onetime_address(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const
|
||||
{
|
||||
crypto::secret_key x, y;
|
||||
if (!try_searching_for_opening_for_onetime_address(address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
x,
|
||||
y))
|
||||
return false;
|
||||
|
||||
// O' = x G + y T
|
||||
rct::key recomputed_onetime_address;
|
||||
rct::addKeys2(recomputed_onetime_address,
|
||||
rct::sk2rct(x),
|
||||
rct::sk2rct(y),
|
||||
rct::pk2rct(crypto::get_T()));
|
||||
|
||||
// O' ?= O
|
||||
return 0 == memcmp(&recomputed_onetime_address, &onetime_address, sizeof(rct::key));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
crypto::key_image carrot_and_legacy_account::derive_key_image(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(can_open_fcmp_onetime_address(
|
||||
address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
onetime_address),
|
||||
"carrot and legacy account: derive key image: cannot open onetime address");
|
||||
|
||||
crypto::secret_key x, y;
|
||||
try_searching_for_opening_for_onetime_address(address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
x,
|
||||
y);
|
||||
|
||||
crypto::key_image L;
|
||||
crypto::generate_key_image(onetime_address, x, L);
|
||||
return L;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
crypto::key_image carrot_and_legacy_account::derive_key_image_view_only(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const
|
||||
{
|
||||
const auto it = subaddress_map.find(address_spend_pubkey);
|
||||
CHECK_AND_ASSERT_THROW_MES(it != subaddress_map.cend(),
|
||||
"carrot and legacy account: derive key image view only: cannot find subaddress");
|
||||
|
||||
const bool is_subaddress = it->second.index.is_subaddress();
|
||||
const uint32_t major_index = it->second.index.major;
|
||||
const uint32_t minor_index = it->second.index.minor;
|
||||
|
||||
const cryptonote::account_keys &keys = get_keys();
|
||||
|
||||
crypto::secret_key address_index_generator;
|
||||
crypto::secret_key subaddress_scalar;
|
||||
crypto::secret_key subaddress_extension;
|
||||
crypto::secret_key address_privkey_g;
|
||||
crypto::secret_key x;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(it->second.derive_type == AddressDeriveType::Carrot,
|
||||
"carrot and legacy account: derive key image view only: not a Carrot address");
|
||||
|
||||
// s^j_gen = H_32[s_ga](j_major, j_minor)
|
||||
make_carrot_index_extension_generator(keys.s_generate_address, major_index, minor_index, address_index_generator);
|
||||
|
||||
if (is_subaddress)
|
||||
{
|
||||
// k^j_subscal = H_n(K_s, j_major, j_minor, s^j_gen)
|
||||
make_carrot_subaddress_scalar(keys.m_carrot_account_address.m_spend_public_key, address_index_generator, major_index, minor_index, subaddress_scalar);
|
||||
}
|
||||
else
|
||||
{
|
||||
// k^j_subscal = 1
|
||||
sc_1(to_bytes(subaddress_scalar));
|
||||
}
|
||||
|
||||
// k^g_a = k_gi * k^j_subscal
|
||||
sc_mul(to_bytes(address_privkey_g), to_bytes(keys.k_generate_image), to_bytes(subaddress_scalar));
|
||||
|
||||
// x = k^{j,g}_addr + k^g_o
|
||||
sc_add(to_bytes(x), to_bytes(address_privkey_g), to_bytes(sender_extension_g));
|
||||
|
||||
crypto::key_image L;
|
||||
crypto::generate_key_image(onetime_address, x, L);
|
||||
return L;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::generate_subaddress_map(const std::pair<size_t, size_t>& lookahead_size)
|
||||
{
|
||||
const std::vector<AddressDeriveType> derive_types{AddressDeriveType::Carrot, AddressDeriveType::PreCarrot};
|
||||
|
||||
for (uint32_t major_index = 0; major_index <= lookahead_size.first; ++major_index)
|
||||
{
|
||||
for (uint32_t minor_index = 0; minor_index <= lookahead_size.second; ++minor_index)
|
||||
{
|
||||
for (const AddressDeriveType derive_type : derive_types)
|
||||
{
|
||||
const subaddress_index_extended subaddr_index{{major_index, minor_index}, derive_type, false};
|
||||
const CarrotDestinationV1 addr = subaddress(subaddr_index);
|
||||
subaddress_map.insert({addr.address_spend_pubkey, subaddr_index});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
crypto::secret_key carrot_and_legacy_account::generate(
|
||||
const crypto::secret_key& recovery_key,
|
||||
bool recover,
|
||||
bool two_random,
|
||||
const AddressDeriveType default_derive_type)
|
||||
{
|
||||
// generate the legacy keys
|
||||
crypto::secret_key retval = cryptonote::account_base::generate(recovery_key, recover, two_random);
|
||||
|
||||
// generate carrot keys
|
||||
set_carrot_keys(default_derive_type);
|
||||
|
||||
return retval;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::set_keys(const cryptonote::account_keys& keys, bool copy_spend_secret_keys)
|
||||
{
|
||||
// CN keys
|
||||
m_keys.m_account_address = keys.m_account_address;
|
||||
if (copy_spend_secret_keys) m_keys.m_spend_secret_key = keys.m_spend_secret_key;
|
||||
m_keys.m_view_secret_key = keys.m_view_secret_key;
|
||||
if (copy_spend_secret_keys) m_keys.m_multisig_keys = keys.m_multisig_keys;
|
||||
m_keys.m_device = keys.m_device;
|
||||
m_keys.m_encryption_iv = keys.m_encryption_iv;
|
||||
|
||||
// Carrot keys
|
||||
if (copy_spend_secret_keys) m_keys.s_master = keys.s_master;
|
||||
if (copy_spend_secret_keys) m_keys.k_prove_spend = keys.k_prove_spend;
|
||||
m_keys.s_view_balance = keys.s_view_balance;
|
||||
m_keys.k_view_incoming = keys.k_view_incoming;
|
||||
m_keys.k_generate_image = keys.k_generate_image;
|
||||
m_keys.s_generate_address = keys.s_generate_address;
|
||||
m_keys.m_carrot_account_address = keys.m_carrot_account_address;
|
||||
m_keys.m_carrot_main_address = keys.m_carrot_main_address;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::create_from_svb_key(const cryptonote::account_public_address& address, const crypto::secret_key& svb_key)
|
||||
{
|
||||
// top level keys
|
||||
m_keys.s_master = crypto::null_skey;
|
||||
make_carrot_provespend_key(m_keys.s_master, m_keys.k_prove_spend);
|
||||
m_keys.s_view_balance = svb_key;
|
||||
|
||||
// view balance keys
|
||||
make_carrot_viewincoming_key(m_keys.s_view_balance, m_keys.k_view_incoming);
|
||||
make_carrot_generateimage_key(m_keys.s_view_balance, m_keys.k_generate_image);
|
||||
make_carrot_generateaddress_secret(m_keys.s_view_balance, m_keys.s_generate_address);
|
||||
|
||||
// carrot account address - use the provided address spend pubkey
|
||||
m_keys.m_carrot_account_address = address;
|
||||
k_view_incoming_dev.view_key_scalar_mult_ed25519(m_keys.m_carrot_account_address.m_spend_public_key,
|
||||
m_keys.m_carrot_account_address.m_view_public_key
|
||||
);
|
||||
|
||||
// carrot main wallet address
|
||||
m_keys.m_carrot_main_address = address;
|
||||
k_view_incoming_dev.view_key_scalar_mult_ed25519(crypto::get_G(),
|
||||
m_keys.m_carrot_main_address.m_view_public_key
|
||||
);
|
||||
|
||||
// Store fields for Carrot
|
||||
m_keys.m_spend_secret_key = crypto::null_skey;
|
||||
m_keys.m_view_secret_key = crypto::null_skey;
|
||||
m_keys.m_account_address = {crypto::null_pkey, crypto::null_pkey, false};
|
||||
|
||||
// Update ALL addresses to be Carrot-only
|
||||
m_keys.m_carrot_account_address.m_is_carrot = true;
|
||||
m_keys.m_carrot_main_address.m_is_carrot = true;
|
||||
|
||||
// Set the default derive type for addresses
|
||||
this->default_derive_type = AddressDeriveType::Carrot;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::set_carrot_keys(const AddressDeriveType default_derive_type)
|
||||
{
|
||||
// top level keys
|
||||
m_keys.s_master = m_keys.m_spend_secret_key;
|
||||
make_carrot_provespend_key(m_keys.s_master, m_keys.k_prove_spend);
|
||||
make_carrot_viewbalance_secret(m_keys.s_master, m_keys.s_view_balance);
|
||||
|
||||
// view balance keys
|
||||
make_carrot_viewincoming_key(m_keys.s_view_balance, m_keys.k_view_incoming);
|
||||
make_carrot_generateimage_key(m_keys.s_view_balance, m_keys.k_generate_image);
|
||||
make_carrot_generateaddress_secret(m_keys.s_view_balance, m_keys.s_generate_address);
|
||||
|
||||
// carrot account address
|
||||
make_carrot_spend_pubkey(m_keys.k_generate_image, m_keys.k_prove_spend, m_keys.m_carrot_account_address.m_spend_public_key);
|
||||
k_view_incoming_dev.view_key_scalar_mult_ed25519(
|
||||
m_keys.m_carrot_account_address.m_spend_public_key,
|
||||
m_keys.m_carrot_account_address.m_view_public_key
|
||||
);
|
||||
m_keys.m_carrot_account_address.m_is_carrot = true;
|
||||
|
||||
// carrot main wallet address
|
||||
m_keys.m_carrot_main_address.m_spend_public_key = m_keys.m_carrot_account_address.m_spend_public_key;
|
||||
k_view_incoming_dev.view_key_scalar_mult_ed25519(
|
||||
crypto::get_G(),
|
||||
m_keys.m_carrot_main_address.m_view_public_key
|
||||
);
|
||||
m_keys.m_carrot_main_address.m_is_carrot = true;
|
||||
|
||||
this->default_derive_type = default_derive_type;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::insert_subaddresses(const std::unordered_map<crypto::public_key, subaddress_index_extended>& subaddress_map_cn)
|
||||
{
|
||||
for (const auto &p : subaddress_map_cn) {
|
||||
subaddress_map.insert({p.first, {{p.second.index.major, p.second.index.minor}, p.second.derive_type, p.second.is_return_spend_key}});
|
||||
if (p.second.derive_type == AddressDeriveType::PreCarrot) {
|
||||
// Create a matching Carrot address
|
||||
const subaddress_index_extended subaddr_index{{p.second.index.major, p.second.index.minor}, AddressDeriveType::Carrot, p.second.is_return_spend_key};
|
||||
const CarrotDestinationV1 addr = subaddress(subaddr_index);
|
||||
subaddress_map.insert({addr.address_spend_pubkey, subaddr_index});
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::insert_return_output_info(const std::unordered_map<crypto::public_key, return_output_info_t>& roi_map)
|
||||
{
|
||||
for (const auto &p : roi_map)
|
||||
return_output_map.insert({p.first, p.second});
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
AddressDeriveType carrot_and_legacy_account::resolve_derive_type(const AddressDeriveType derive_type) const
|
||||
{
|
||||
return derive_type == AddressDeriveType::Auto ? default_derive_type : derive_type;
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -0,0 +1,242 @@
|
||||
// Copyright (c) 2025, 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 "account_secrets.h"
|
||||
#include "address_utils.h"
|
||||
#include "destination.h"
|
||||
#include "device_ram_borrowed.h"
|
||||
#include "enote_utils.h"
|
||||
#include "carrot_impl/subaddress_index.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_basic/subaddress_index.h"
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
static constexpr std::uint32_t MAX_SUBADDRESS_MAJOR_INDEX = 5;
|
||||
static constexpr std::uint32_t MAX_SUBADDRESS_MINOR_INDEX = 20;
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
|
||||
struct return_output_info_t {
|
||||
input_context_t input_context;
|
||||
crypto::public_key K_o; // output onetime address
|
||||
crypto::public_key K_change; // change output onetime address
|
||||
crypto::public_key K_spend_pubkey; // change output spend pubkey
|
||||
crypto::key_image key_image;
|
||||
crypto::secret_key sum_g;
|
||||
crypto::secret_key sender_extension_t;
|
||||
|
||||
return_output_info_t() {
|
||||
// Default constructor for serialization
|
||||
input_context = input_context_t();
|
||||
K_o = crypto::public_key();
|
||||
K_change = crypto::public_key();
|
||||
K_spend_pubkey = crypto::public_key();
|
||||
key_image = crypto::key_image();
|
||||
sum_g = crypto::secret_key();
|
||||
sender_extension_t = crypto::secret_key();
|
||||
}
|
||||
|
||||
return_output_info_t(
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &K_o,
|
||||
const crypto::public_key &K_change,
|
||||
const crypto::public_key &K_spend_pubkey,
|
||||
const crypto::key_image &key_image,
|
||||
const crypto::secret_key &sum_g,
|
||||
const crypto::secret_key &sender_extension_t):
|
||||
input_context(input_context),
|
||||
K_o(K_o),
|
||||
K_change(K_change),
|
||||
K_spend_pubkey(K_spend_pubkey),
|
||||
key_image(key_image),
|
||||
sum_g(sum_g),
|
||||
sender_extension_t(sender_extension_t) {}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(input_context)
|
||||
FIELD(K_o)
|
||||
FIELD(K_change)
|
||||
FIELD(K_spend_pubkey)
|
||||
FIELD(key_image)
|
||||
FIELD(sum_g)
|
||||
FIELD(sender_extension_t)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
// Old return_output_info_t format (for deserializing version 2 wallet caches)
|
||||
struct return_output_info_retired_t {
|
||||
input_context_t input_context;
|
||||
crypto::public_key K_o;
|
||||
crypto::public_key K_change;
|
||||
crypto::key_image key_image;
|
||||
crypto::secret_key x;
|
||||
crypto::secret_key y;
|
||||
|
||||
return_output_info_retired_t() {
|
||||
input_context = input_context_t();
|
||||
K_o = crypto::public_key();
|
||||
K_change = crypto::public_key();
|
||||
key_image = crypto::key_image();
|
||||
x = crypto::secret_key();
|
||||
y = crypto::secret_key();
|
||||
}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(input_context)
|
||||
FIELD(K_o)
|
||||
FIELD(K_change)
|
||||
FIELD(key_image)
|
||||
FIELD(x)
|
||||
FIELD(y)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
class carrot_and_legacy_account : public cryptonote::account_base
|
||||
{
|
||||
public:
|
||||
view_incoming_key_ram_borrowed_device k_view_incoming_dev;
|
||||
view_balance_secret_ram_borrowed_device s_view_balance_dev;
|
||||
generate_address_secret_ram_borrowed_device s_generate_address_dev;
|
||||
|
||||
AddressDeriveType default_derive_type;
|
||||
|
||||
carrot_and_legacy_account(): k_view_incoming_dev(get_keys().k_view_incoming),
|
||||
s_view_balance_dev(get_keys().s_view_balance),
|
||||
s_generate_address_dev(get_keys().s_generate_address)
|
||||
{}
|
||||
|
||||
void set_keys(const cryptonote::account_keys& keys, bool copy_spend_secret_keys);
|
||||
|
||||
carrot_and_legacy_account(const carrot_and_legacy_account &k) = delete;
|
||||
carrot_and_legacy_account(carrot_and_legacy_account&&) = delete;
|
||||
|
||||
carrot_and_legacy_account& operator=(const carrot_and_legacy_account&) = delete;
|
||||
carrot_and_legacy_account& operator=(carrot_and_legacy_account&&) = delete;
|
||||
|
||||
CarrotDestinationV1 cryptonote_address(const payment_id_t payment_id = null_payment_id,
|
||||
const AddressDeriveType derive_type = AddressDeriveType::Auto) const;
|
||||
|
||||
CarrotDestinationV1 subaddress(const subaddress_index_extended &subaddress_index) const;
|
||||
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> get_subaddress_map_cn() const;
|
||||
const std::unordered_map<crypto::public_key, subaddress_index_extended>& get_subaddress_map_ref() const;
|
||||
const std::unordered_map<crypto::public_key, return_output_info_t>& get_return_output_map_ref() const;
|
||||
|
||||
// brief: opening_for_subaddress - return (k^g_a, k^t_a) for j s.t. K^j_s = (k^g_a * G + k^t_a * T)
|
||||
void opening_for_subaddress(const subaddress_index_extended &subaddress_index,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
crypto::secret_key &address_privkey_t_out,
|
||||
crypto::public_key &address_spend_pubkey_out) const;
|
||||
|
||||
bool try_searching_for_opening_for_subaddress(const crypto::public_key &address_spend_pubkey,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
crypto::secret_key &address_privkey_t_out) const;
|
||||
|
||||
bool try_searching_for_opening_for_onetime_address(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
crypto::secret_key &x_out,
|
||||
crypto::secret_key &y_out) const;
|
||||
|
||||
bool can_open_fcmp_onetime_address(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const;
|
||||
|
||||
crypto::key_image derive_key_image(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const;
|
||||
|
||||
crypto::key_image derive_key_image_view_only(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const;
|
||||
|
||||
void generate_subaddress_map(const std::pair<size_t, size_t>& lookahead_size);
|
||||
|
||||
crypto::secret_key generate(
|
||||
const crypto::secret_key& recovery_key = crypto::secret_key(),
|
||||
bool recover = false,
|
||||
bool two_random = false,
|
||||
const AddressDeriveType default_derive_type = AddressDeriveType::Carrot
|
||||
);
|
||||
|
||||
void create_from_svb_key(const cryptonote::account_public_address& address, const crypto::secret_key& svb_key);
|
||||
void set_carrot_keys(const AddressDeriveType default_derive_type = AddressDeriveType::Carrot);
|
||||
void insert_subaddresses(const std::unordered_map<crypto::public_key, subaddress_index_extended>& subaddress_map);
|
||||
void insert_return_output_info(
|
||||
const std::unordered_map<crypto::public_key, return_output_info_t>& input_context_map
|
||||
);
|
||||
|
||||
AddressDeriveType resolve_derive_type(const AddressDeriveType derive_type) const;
|
||||
|
||||
private:
|
||||
std::unordered_map<crypto::public_key, subaddress_index_extended> subaddress_map;
|
||||
// Kr -> return_output_info
|
||||
std::unordered_map<crypto::public_key, return_output_info_t> return_output_map;
|
||||
};
|
||||
}
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template <class Archive>
|
||||
inline typename std::enable_if<!Archive::is_loading::value, void>::type initialize_transfer_details(Archive &a, carrot::return_output_info_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
}
|
||||
template <class Archive>
|
||||
inline typename std::enable_if<Archive::is_loading::value, void>::type initialize_transfer_details(Archive &a, carrot::return_output_info_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.input_context = carrot::input_context_t();
|
||||
x.K_o = crypto::public_key();
|
||||
x.K_change = crypto::public_key();
|
||||
x.K_spend_pubkey = crypto::public_key();
|
||||
x.key_image = crypto::key_image();
|
||||
x.sum_g = crypto::secret_key();
|
||||
x.sender_extension_t = crypto::secret_key();
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, carrot::return_output_info_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.input_context;
|
||||
a & x.K_o;
|
||||
a & x.K_change;
|
||||
a & x.K_spend_pubkey;
|
||||
a & x.key_image;
|
||||
a & x.sum_g;
|
||||
a & x.sender_extension_t;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,8 @@ struct CarrotEnoteV1 final
|
||||
mx25519_pubkey enote_ephemeral_pubkey;
|
||||
/// L_0
|
||||
crypto::key_image tx_first_key_image;
|
||||
// transaction output keys
|
||||
std::vector<crypto::public_key> tx_output_keys;
|
||||
};
|
||||
|
||||
/// equality operators
|
||||
|
||||
@@ -70,10 +70,11 @@ static constexpr const unsigned char CARROT_DOMAIN_SEP_SUBADDRESS_SCALAR[] = "Ca
|
||||
static constexpr const unsigned int CARROT_MIN_TX_OUTPUTS = 2;
|
||||
static constexpr const unsigned int CARROT_MAX_TX_OUTPUTS = 8;
|
||||
static constexpr const unsigned int CARROT_MIN_TX_INPUTS = 1;
|
||||
static constexpr const unsigned int CARROT_MAX_TX_INPUTS = 8;
|
||||
static constexpr const unsigned int CARROT_MAX_TX_INPUTS = 64;
|
||||
|
||||
// SPARC addressing protocol domain separators
|
||||
static constexpr const unsigned char SPARC_DOMAIN_SEP_RETURN_PUBKEY_ENCRYPTION_MASK[] = "SPARC return pubkey encryption mask";
|
||||
static constexpr const unsigned char SPARC_DOMAIN_SEP_RETURN_ADDRESS_SCALAR[] = "SPARC return address scalar";
|
||||
static constexpr const unsigned char SPARC_DOMAIN_SEP_RETURN_INDEX_SCALAR[] = "SPARC return index scalar";
|
||||
|
||||
} //namespace carrot
|
||||
|
||||
@@ -122,6 +122,11 @@ bool operator==(const view_tag_t &a, const view_tag_t &b)
|
||||
return memcmp(&a, &b, sizeof(view_tag_t)) == 0;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool operator==(const rollup_binding_tag_t &a, const rollup_binding_tag_t &b)
|
||||
{
|
||||
return memcmp(&a, &b, sizeof(rollup_binding_tag_t)) == 0;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
janus_anchor_t gen_janus_anchor()
|
||||
{
|
||||
return crypto::rand<janus_anchor_t>();
|
||||
|
||||
@@ -106,6 +106,13 @@ struct encrypted_return_pubkey_t final
|
||||
unsigned char bytes[ENCRYPTED_RETURN_PUBKEY_BYTES];
|
||||
};
|
||||
|
||||
/// Salvium rollup binding tag
|
||||
constexpr std::size_t ROLLUP_BINDING_TAG_BYTES{8};
|
||||
struct rollup_binding_tag_t final
|
||||
{
|
||||
unsigned char bytes[ROLLUP_BINDING_TAG_BYTES];
|
||||
};
|
||||
|
||||
/// overloaded operators: address tag
|
||||
bool operator==(const janus_anchor_t &a, const janus_anchor_t &b);
|
||||
static inline bool operator!=(const janus_anchor_t &a, const janus_anchor_t &b) { return !(a == b); }
|
||||
@@ -139,6 +146,10 @@ bool operator==(const encrypted_return_pubkey_t &a, const encrypted_return_pubke
|
||||
static inline bool operator!=(const encrypted_return_pubkey_t &a, const encrypted_return_pubkey_t &b) { return !(a == b); }
|
||||
encrypted_return_pubkey_t operator^(const encrypted_return_pubkey_t &a, const encrypted_return_pubkey_t &b);
|
||||
|
||||
/// overloaded operators: rollup binding tag
|
||||
bool operator==(const rollup_binding_tag_t &a, const rollup_binding_tag_t &b);
|
||||
static inline bool operator!=(const rollup_binding_tag_t &a, const rollup_binding_tag_t &b) { return !(a == b); }
|
||||
|
||||
/// generate a random janus anchor
|
||||
janus_anchor_t gen_janus_anchor();
|
||||
/// generate a random (non-null) payment ID
|
||||
|
||||
@@ -134,6 +134,10 @@ struct view_incoming_key_device
|
||||
const crypto::public_key &onetime_address,
|
||||
janus_anchor_t &anchor_special_out) const = 0;
|
||||
|
||||
virtual void make_internal_return_privkey(const input_context_t &input_context,
|
||||
const crypto::public_key &onetime_address,
|
||||
crypto::secret_key &return_privkey_out) const = 0;
|
||||
|
||||
virtual ~view_incoming_key_device() = default;
|
||||
};
|
||||
|
||||
|
||||
@@ -55,6 +55,13 @@ bool view_incoming_key_ram_borrowed_device::view_key_scalar_mult_x25519(const mx
|
||||
return make_carrot_uncontextualized_shared_key_receiver(m_k_view_incoming, D, kvD);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void view_incoming_key_ram_borrowed_device::make_internal_return_privkey(const input_context_t &input_context,
|
||||
const crypto::public_key &onetime_address,
|
||||
crypto::secret_key &return_privkey_out) const
|
||||
{
|
||||
make_sparc_return_privkey(to_bytes(m_k_view_incoming), input_context, onetime_address, return_privkey_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void view_incoming_key_ram_borrowed_device::make_janus_anchor_special(
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey,
|
||||
const input_context_t &input_context,
|
||||
|
||||
@@ -60,6 +60,10 @@ public:
|
||||
const crypto::public_key &onetime_address,
|
||||
janus_anchor_t &anchor_special_out) const override;
|
||||
|
||||
void make_internal_return_privkey(const input_context_t &input_context,
|
||||
const crypto::public_key &onetime_address,
|
||||
crypto::secret_key &return_privkey_out) const override;
|
||||
|
||||
protected:
|
||||
const crypto::secret_key &m_k_view_incoming;
|
||||
};
|
||||
|
||||
@@ -39,6 +39,7 @@ extern "C"
|
||||
#include "crypto/wallet/crypto.h"
|
||||
#include "hash_functions.h"
|
||||
#include "int-util.h"
|
||||
#include "string_tools.h"
|
||||
#include "misc_language.h"
|
||||
#include "ringct/rctOps.h"
|
||||
#include "transcript_fixed.h"
|
||||
@@ -211,6 +212,17 @@ void make_sparc_return_privkey(const unsigned char s_sender_receiver_unctx[32],
|
||||
derive_scalar(transcript.data(), transcript.size(), s_sender_receiver_unctx, &return_privkey_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void make_sparc_return_index(const unsigned char s_sender_receiver_unctx[32],
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &onetime_address,
|
||||
const uint64_t idx,
|
||||
crypto::secret_key &return_index_out)
|
||||
{
|
||||
// k_idx = H_32(s_sr || input_context || Ko || idx)
|
||||
const auto transcript = sp::make_fixed_transcript<SPARC_DOMAIN_SEP_RETURN_INDEX_SCALAR>(input_context, onetime_address, idx);
|
||||
derive_scalar(transcript.data(), transcript.size(), s_sender_receiver_unctx, &return_index_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void make_sparc_return_pubkey_encryption_mask(const unsigned char s_sender_receiver_unctx[32],
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &onetime_address,
|
||||
@@ -221,6 +233,54 @@ void make_sparc_return_pubkey_encryption_mask(const unsigned char s_sender_recei
|
||||
derive_bytes_32(transcript.data(), transcript.size(), s_sender_receiver_unctx, &return_pubkey_mask_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void make_sparc_return_pubkey(const unsigned char s_sender_receiver_unctx[32],
|
||||
const input_context_t &input_context,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const crypto::public_key &onetime_address,
|
||||
const uint64_t idx,
|
||||
encrypted_return_pubkey_t &return_pubkey_out)
|
||||
{
|
||||
// compute k_return
|
||||
crypto::secret_key k_return;
|
||||
s_view_balance_dev->make_internal_return_privkey(input_context, onetime_address, k_return);
|
||||
|
||||
// compute k_idx
|
||||
crypto::secret_key k_idx;
|
||||
make_sparc_return_index(s_sender_receiver_unctx, input_context, onetime_address, idx, k_idx);
|
||||
|
||||
// compute m_return
|
||||
encrypted_return_pubkey_t m_return;
|
||||
make_sparc_return_pubkey_encryption_mask(s_sender_receiver_unctx,
|
||||
input_context,
|
||||
onetime_address,
|
||||
m_return);
|
||||
|
||||
#if 1
|
||||
// compute SPARC K_return = k_return * G
|
||||
crypto::public_key K_return;
|
||||
crypto::secret_key_to_public_key(k_return, K_return);
|
||||
|
||||
// compute return_enc
|
||||
encrypted_return_pubkey_t return_pub;
|
||||
static_assert(sizeof(K_return.data) == sizeof(return_pub.bytes), "Size mismatch");
|
||||
memcpy(return_pub.bytes, K_return.data, sizeof(encrypted_return_pubkey_t));
|
||||
#else
|
||||
// compute SPARC K_return = k_return * G + k_idx * T
|
||||
rct::key K_return;
|
||||
rct::addKeys2(K_return,
|
||||
rct::sk2rct(k_return),
|
||||
rct::sk2rct(k_idx),
|
||||
rct::pk2rct(crypto::get_T()));
|
||||
|
||||
// compute return_enc
|
||||
encrypted_return_pubkey_t return_pub;
|
||||
static_assert(sizeof(K_return.bytes) == sizeof(return_pub.bytes), "Size mismatch");
|
||||
memcpy(return_pub.bytes, K_return.bytes, sizeof(encrypted_return_pubkey_t));
|
||||
#endif
|
||||
return_pubkey_out = return_pub ^ m_return;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
input_context_t make_carrot_input_context_coinbase(const std::uint64_t block_index)
|
||||
{
|
||||
// input_context = "C" || IntToBytes256(block_index)
|
||||
@@ -450,7 +510,6 @@ bool test_carrot_view_tag(const unsigned char s_sender_receiver_unctx[32],
|
||||
// vt' = H_3(s_sr || input_context || Ko)
|
||||
view_tag_t nominal_view_tag;
|
||||
make_carrot_view_tag(s_sender_receiver_unctx, input_context, onetime_address, nominal_view_tag);
|
||||
|
||||
// vt' ?= vt
|
||||
return nominal_view_tag == view_tag;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "core_types.h"
|
||||
#include "mx25519.h"
|
||||
#include "ringct/rctTypes.h"
|
||||
#include "device.h"
|
||||
|
||||
//third party headers
|
||||
|
||||
@@ -137,6 +138,20 @@ void make_sparc_return_privkey(const unsigned char s_sender_receiver_unctx[32],
|
||||
const crypto::public_key &onetime_address,
|
||||
crypto::secret_key &return_privkey_out);
|
||||
/**
|
||||
* brief: make_sparc_return_index - return index, given non-secret data
|
||||
* m_return = H_32(s_sr || input_context || Ko || idx)
|
||||
* param: s_sender_receiver_unctx - s_sr
|
||||
* param: input_context - input_context
|
||||
* param: onetime_address - Ko
|
||||
* param: idx - idx
|
||||
* outparam: return_index_out - m_return
|
||||
*/
|
||||
void make_sparc_return_index(const unsigned char s_sender_receiver_unctx[32],
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &onetime_address,
|
||||
const uint64_t idx,
|
||||
crypto::secret_key &return_index_out);
|
||||
/**
|
||||
* brief: make_sparc_return_pubkey_encryption_mask - used for hiding return pubkey
|
||||
* m_return = H_32(s_sr || input_context || Ko)
|
||||
* param: s_sender_receiver_unctx - s_sr
|
||||
@@ -148,6 +163,21 @@ void make_sparc_return_pubkey_encryption_mask(const unsigned char s_sender_recei
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &onetime_address,
|
||||
encrypted_return_pubkey_t &return_pubkey_mask_out);
|
||||
|
||||
/**
|
||||
* brief: make_sparc_return_pubkey - construct the return pubkey
|
||||
* param: s_sender_receiver_unctx - s_sr
|
||||
* param: input_context - input_context
|
||||
* param: s_view_balance_dev - s_vb
|
||||
* param: onetime_address - Ko
|
||||
* outparam: return_pubkey_mask_out - K_return
|
||||
*/
|
||||
void make_sparc_return_pubkey(const unsigned char s_sender_receiver_unctx[32],
|
||||
const input_context_t &input_context,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const crypto::public_key &onetime_address,
|
||||
const uint64_t idx,
|
||||
encrypted_return_pubkey_t &return_pubkey_out);
|
||||
/**
|
||||
* brief: make_carrot_input_context_coinbase - input context for a sender-receiver secret (coinbase txs)
|
||||
* input_context = "C" || IntToBytes256(block_index)
|
||||
|
||||
@@ -41,9 +41,9 @@
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
#define CARROT_DEFINE_SIMPLE_ERROR_TYPE(e, b) class e: b { using b::b; };
|
||||
#define CARROT_DEFINE_SIMPLE_ERROR_TYPE(e, b) class e: public b { using b::b; };
|
||||
|
||||
class carrot_logic_error: std::logic_error { using std::logic_error::logic_error; };
|
||||
class carrot_logic_error: public std::logic_error { using std::logic_error::logic_error; };
|
||||
|
||||
CARROT_DEFINE_SIMPLE_ERROR_TYPE(bad_address_type, carrot_logic_error)
|
||||
CARROT_DEFINE_SIMPLE_ERROR_TYPE(component_out_of_order, carrot_logic_error)
|
||||
@@ -55,7 +55,7 @@ CARROT_DEFINE_SIMPLE_ERROR_TYPE(too_few_outputs, carrot_logic_error)
|
||||
CARROT_DEFINE_SIMPLE_ERROR_TYPE(too_many_outputs, carrot_logic_error)
|
||||
CARROT_DEFINE_SIMPLE_ERROR_TYPE(invalid_tx_type, carrot_logic_error)
|
||||
|
||||
class carrot_runtime_error: std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
class carrot_runtime_error: public std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
CARROT_DEFINE_SIMPLE_ERROR_TYPE(crypto_function_failed, carrot_runtime_error)
|
||||
CARROT_DEFINE_SIMPLE_ERROR_TYPE(not_enough_money, carrot_runtime_error)
|
||||
|
||||
@@ -77,7 +77,7 @@ std::optional<AdditionalOutputType> get_additional_output_type(const size_t num_
|
||||
}
|
||||
else if (!need_change_output)
|
||||
{
|
||||
return AdditionalOutputType::DUMMY;
|
||||
return AdditionalOutputType::CHANGE_UNIQUE;
|
||||
}
|
||||
else // num_selfsend == 1 && need_change_output
|
||||
{
|
||||
@@ -159,8 +159,11 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
const view_incoming_key_device *k_view_dev,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
std::vector<RCTOutputEnoteProposal> &output_enote_proposals_out,
|
||||
RCTOutputEnoteProposal &return_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out,
|
||||
cryptonote::transaction_type tx_type,
|
||||
size_t &change_index_out,
|
||||
std::unordered_map<crypto::public_key, size_t> &payments_indices_out,
|
||||
std::vector<std::pair<bool, std::size_t>> *payment_proposal_order_out)
|
||||
{
|
||||
output_enote_proposals_out.clear();
|
||||
@@ -171,7 +174,14 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
// assert payment proposals numbers
|
||||
const size_t num_selfsend_proposals = selfsend_payment_proposals.size();
|
||||
const size_t num_proposals = normal_payment_proposals.size() + num_selfsend_proposals;
|
||||
CARROT_CHECK_AND_THROW(num_proposals >= CARROT_MIN_TX_OUTPUTS, too_few_outputs, "too few payment proposals");
|
||||
if (tx_type == cryptonote::transaction_type::STAKE ||
|
||||
tx_type == cryptonote::transaction_type::BURN ||
|
||||
tx_type == cryptonote::transaction_type::CREATE_TOKEN ||
|
||||
tx_type == cryptonote::transaction_type::ROLLUP) {
|
||||
CARROT_CHECK_AND_THROW(num_proposals == 1, too_few_outputs, "tx doesn't have correct number of proposals");
|
||||
} else {
|
||||
CARROT_CHECK_AND_THROW(num_proposals >= CARROT_MIN_TX_OUTPUTS, too_few_outputs, "too few payment proposals");
|
||||
}
|
||||
CARROT_CHECK_AND_THROW(num_proposals <= CARROT_MAX_TX_OUTPUTS, too_many_outputs, "too many payment proposals");
|
||||
CARROT_CHECK_AND_THROW(num_selfsend_proposals, too_few_outputs, "no selfsend payment proposal");
|
||||
|
||||
@@ -203,17 +213,30 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
// D^other_e
|
||||
std::optional<mx25519_pubkey> other_enote_ephemeral_pubkey;
|
||||
|
||||
// map destinations to output keys in order to find the indices of these outputs in tx
|
||||
std::unordered_map<crypto::public_key, crypto::public_key> output_destinations_to_keys;
|
||||
|
||||
// construct normal enotes
|
||||
for (size_t i = 0; i < normal_payment_proposals.size(); ++i)
|
||||
{
|
||||
auto &output_entry = tools::add_element(sortable_data);
|
||||
auto &output_entry = sortable_data.emplace_back();
|
||||
output_entry.second = {false, i};
|
||||
|
||||
encrypted_payment_id_t encrypted_payment_id;
|
||||
get_output_proposal_normal_v1(normal_payment_proposals[i],
|
||||
tx_first_key_image,
|
||||
output_entry.first,
|
||||
encrypted_payment_id);
|
||||
if (tx_type == cryptonote::transaction_type::RETURN) {
|
||||
const uint64_t idx = 0;
|
||||
get_output_proposal_return_v1(normal_payment_proposals[i],
|
||||
tx_first_key_image,
|
||||
s_view_balance_dev,
|
||||
output_entry.first,
|
||||
encrypted_payment_id);
|
||||
} else {
|
||||
get_output_proposal_normal_v1(normal_payment_proposals[i],
|
||||
tx_first_key_image,
|
||||
s_view_balance_dev,
|
||||
output_entry.first,
|
||||
encrypted_payment_id);
|
||||
}
|
||||
|
||||
// if 1 normal, and 2 self-send, set D^other_e equal to this D_e
|
||||
if (num_proposals == 2)
|
||||
@@ -223,6 +246,11 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
const bool is_integrated = normal_payment_proposals[i].destination.payment_id != null_payment_id;
|
||||
if (is_integrated)
|
||||
encrypted_payment_id_out = encrypted_payment_id;
|
||||
|
||||
// save the one time key for this destination
|
||||
output_destinations_to_keys.insert(
|
||||
{output_entry.first.enote.onetime_address, normal_payment_proposals[i].destination.address_spend_pubkey}
|
||||
);
|
||||
}
|
||||
|
||||
// in the case that there is no required pid_enc, set it to the provided dummy
|
||||
@@ -246,7 +274,7 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
{
|
||||
const CarrotPaymentProposalSelfSendV1 &selfsend_payment_proposal = selfsend_payment_proposals.at(i);
|
||||
|
||||
auto &output_entry = tools::add_element(sortable_data);
|
||||
auto &output_entry = sortable_data.emplace_back();
|
||||
output_entry.second = {true, i};
|
||||
|
||||
if (s_view_balance_dev != nullptr)
|
||||
@@ -255,6 +283,8 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
*s_view_balance_dev,
|
||||
tx_first_key_image,
|
||||
other_enote_ephemeral_pubkey,
|
||||
tx_type,
|
||||
return_enote_out,
|
||||
output_entry.first);
|
||||
}
|
||||
else if (k_view_dev != nullptr)
|
||||
@@ -270,10 +300,16 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
CARROT_THROW(std::invalid_argument, "neither a view-balance nor view-incoming device was provided");
|
||||
}
|
||||
|
||||
// save the change one time key
|
||||
if (selfsend_payment_proposal.enote_type == CarrotEnoteType::CHANGE)
|
||||
{
|
||||
change_address = output_entry.first.enote.onetime_address;
|
||||
}
|
||||
|
||||
// save the one time key for this destination
|
||||
output_destinations_to_keys.insert(
|
||||
{output_entry.first.enote.onetime_address, selfsend_payment_proposal.destination_address_spend_pubkey}
|
||||
);
|
||||
}
|
||||
|
||||
// sort enotes by K_o
|
||||
@@ -287,8 +323,13 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
if (sortable_data[i].first.enote.onetime_address == change_address)
|
||||
{
|
||||
change_index_out = i;
|
||||
break;
|
||||
}
|
||||
|
||||
// map destinations to output indices
|
||||
const auto spend_key = output_destinations_to_keys[sortable_data[i].first.enote.onetime_address];
|
||||
payments_indices_out.insert(
|
||||
{spend_key, i}
|
||||
);
|
||||
}
|
||||
|
||||
// collect output_enote_proposals_out and payment_proposal_order_out
|
||||
@@ -324,11 +365,11 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
component_out_of_order, "this set contains duplicate onetime addresses");
|
||||
|
||||
// assert all K_o lie in prime order subgroup
|
||||
for (const RCTOutputEnoteProposal &output_enote_proposal : output_enote_proposals_out)
|
||||
{
|
||||
CARROT_CHECK_AND_THROW(rct::isInMainSubgroup(rct::pk2rct(output_enote_proposal.enote.onetime_address)),
|
||||
invalid_point, "this set contains an invalid onetime address");
|
||||
}
|
||||
// for (const RCTOutputEnoteProposal &output_enote_proposal : output_enote_proposals_out)
|
||||
// {
|
||||
// CARROT_CHECK_AND_THROW(rct::isInMainSubgroup(rct::pk2rct(output_enote_proposal.enote.onetime_address)),
|
||||
// invalid_point, "this set contains an invalid onetime address");
|
||||
// }
|
||||
|
||||
// assert unique and non-trivial k_a
|
||||
memcmp_set<crypto::secret_key> amount_blinding_factors;
|
||||
@@ -379,7 +420,7 @@ void get_coinbase_output_enotes(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
{
|
||||
get_coinbase_output_proposal_v1(normal_payment_proposals[i],
|
||||
block_index,
|
||||
tools::add_element(output_coinbase_enotes_out));
|
||||
output_coinbase_enotes_out.emplace_back());
|
||||
}
|
||||
|
||||
// assert uniqueness and non-trivial-ness of D_e
|
||||
|
||||
@@ -109,8 +109,11 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
const view_incoming_key_device *k_view_dev,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
std::vector<RCTOutputEnoteProposal> &output_enote_proposals_out,
|
||||
RCTOutputEnoteProposal &return_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out,
|
||||
cryptonote::transaction_type tx_type,
|
||||
size_t &change_index_out,
|
||||
std::unordered_map<crypto::public_key, size_t> &payments_indices_out,
|
||||
std::vector<std::pair<bool, std::size_t>> *payment_proposal_order_out = nullptr);
|
||||
/**
|
||||
* brief: get_coinbase_output_enotes - convert a *finalized* set of payment proposals into coinbase output enotes
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "misc_language.h"
|
||||
#include "misc_log_ex.h"
|
||||
#include "ringct/rctOps.h"
|
||||
#include "crypto/generators.h"
|
||||
|
||||
//third party headers
|
||||
|
||||
@@ -170,6 +171,7 @@ static void get_external_output_proposal_parts(const mx25519_pubkey &s_sender_re
|
||||
const CarrotEnoteType enote_type,
|
||||
const mx25519_pubkey &enote_ephemeral_pubkey,
|
||||
const input_context_t &input_context,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const bool coinbase_amount_commitment,
|
||||
crypto::hash &s_sender_receiver_out,
|
||||
crypto::secret_key &amount_blinding_factor_out,
|
||||
@@ -177,7 +179,8 @@ static void get_external_output_proposal_parts(const mx25519_pubkey &s_sender_re
|
||||
crypto::public_key &onetime_address_out,
|
||||
encrypted_amount_t &encrypted_amount_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out,
|
||||
view_tag_t &view_tag_out)
|
||||
view_tag_t &view_tag_out,
|
||||
encrypted_return_pubkey_t &return_pubkey_out)
|
||||
{
|
||||
// 1. s^ctx_sr = H_32(s_sr, D_e, input_context)
|
||||
make_carrot_sender_receiver_secret(s_sender_receiver_unctx.data,
|
||||
@@ -202,6 +205,15 @@ static void get_external_output_proposal_parts(const mx25519_pubkey &s_sender_re
|
||||
|
||||
// 3. vt = H_3(s_sr || input_context || Ko)
|
||||
make_carrot_view_tag(s_sender_receiver_unctx.data, input_context, onetime_address_out, view_tag_out);
|
||||
|
||||
// 4. construct the return pubkey
|
||||
if (s_view_balance_dev != nullptr)
|
||||
make_sparc_return_pubkey(s_sender_receiver_unctx.data,
|
||||
input_context,
|
||||
s_view_balance_dev,
|
||||
onetime_address_out,
|
||||
0,
|
||||
return_pubkey_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -209,6 +221,7 @@ bool operator==(const CarrotPaymentProposalV1 &a, const CarrotPaymentProposalV1
|
||||
{
|
||||
return a.destination == b.destination &&
|
||||
a.amount == b.amount &&
|
||||
a.asset_type == b.asset_type &&
|
||||
a.randomness == b.randomness;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -218,6 +231,7 @@ bool operator==(const CarrotPaymentProposalSelfSendV1 &a, const CarrotPaymentPro
|
||||
a.amount == b.amount &&
|
||||
a.enote_type == b.enote_type &&
|
||||
a.internal_message == b.internal_message &&
|
||||
a.asset_type == b.asset_type &&
|
||||
0 == memcmp(&a.enote_ephemeral_pubkey, &b.enote_ephemeral_pubkey, sizeof(mx25519_pubkey));
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -257,6 +271,7 @@ void get_coinbase_output_proposal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
|
||||
// 4. build the output enote address pieces
|
||||
crypto::hash s_sender_receiver; auto q_wiper = auto_wiper(s_sender_receiver);
|
||||
encrypted_return_pubkey_t return_pubkey_out;
|
||||
crypto::secret_key dummy_amount_blinding_factor;
|
||||
rct::key dummy_amount_commitment;
|
||||
encrypted_amount_t dummy_encrypted_amount;
|
||||
@@ -268,6 +283,7 @@ void get_coinbase_output_proposal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
CarrotEnoteType::PAYMENT,
|
||||
output_enote_out.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
nullptr, // s_view_balance_dev
|
||||
true, // coinbase_amount_commitment
|
||||
s_sender_receiver,
|
||||
dummy_amount_blinding_factor,
|
||||
@@ -275,8 +291,9 @@ void get_coinbase_output_proposal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
output_enote_out.onetime_address,
|
||||
dummy_encrypted_amount,
|
||||
dummy_encrypted_payment_id,
|
||||
output_enote_out.view_tag);
|
||||
|
||||
output_enote_out.view_tag,
|
||||
return_pubkey_out);
|
||||
|
||||
// 5. anchor_enc = anchor XOR m_anchor
|
||||
output_enote_out.anchor_enc = encrypt_carrot_anchor(proposal.randomness,
|
||||
s_sender_receiver,
|
||||
@@ -290,6 +307,7 @@ void get_coinbase_output_proposal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out)
|
||||
{
|
||||
@@ -309,6 +327,7 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
|
||||
// 4. build the output enote address pieces
|
||||
crypto::hash s_sender_receiver; auto q_wiper = auto_wiper(s_sender_receiver);
|
||||
encrypted_return_pubkey_t return_pubkey;
|
||||
get_external_output_proposal_parts(s_sender_receiver_unctx,
|
||||
proposal.destination.address_spend_pubkey,
|
||||
proposal.destination.payment_id,
|
||||
@@ -316,6 +335,7 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
CarrotEnoteType::PAYMENT,
|
||||
output_enote_out.enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
s_view_balance_dev, // we need it to calculate the return pubkey
|
||||
false, // coinbase_amount_commitment
|
||||
s_sender_receiver,
|
||||
output_enote_out.amount_blinding_factor,
|
||||
@@ -323,17 +343,19 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
output_enote_out.enote.onetime_address,
|
||||
output_enote_out.enote.amount_enc,
|
||||
encrypted_payment_id_out,
|
||||
output_enote_out.enote.view_tag);
|
||||
|
||||
output_enote_out.enote.view_tag,
|
||||
return_pubkey);
|
||||
|
||||
// 5. anchor_enc = anchor XOR m_anchor
|
||||
output_enote_out.enote.anchor_enc = encrypt_carrot_anchor(proposal.randomness,
|
||||
s_sender_receiver,
|
||||
output_enote_out.enote.onetime_address);
|
||||
|
||||
// 6. save the amount and first key image
|
||||
output_enote_out.amount = proposal.amount;
|
||||
output_enote_out.enote.asset_type = proposal.asset_type;
|
||||
output_enote_out.enote.tx_first_key_image = tx_first_key_image;
|
||||
output_enote_out.amount = proposal.amount;
|
||||
output_enote_out.enote.asset_type = proposal.asset_type;
|
||||
output_enote_out.enote.tx_first_key_image = tx_first_key_image;
|
||||
output_enote_out.enote.return_enc = return_pubkey;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &proposal,
|
||||
@@ -368,6 +390,7 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
|
||||
|
||||
// 5. build the output enote address pieces
|
||||
crypto::hash s_sender_receiver; auto q_wiper = auto_wiper(s_sender_receiver);
|
||||
encrypted_return_pubkey_t return_pubkey_out;
|
||||
encrypted_payment_id_t dummy_encrypted_payment_id;
|
||||
get_external_output_proposal_parts(s_sender_receiver_unctx,
|
||||
proposal.destination_address_spend_pubkey,
|
||||
@@ -376,6 +399,7 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
|
||||
proposal.enote_type,
|
||||
enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
nullptr,
|
||||
false, // coinbase_amount_commitment
|
||||
s_sender_receiver,
|
||||
output_enote_out.amount_blinding_factor,
|
||||
@@ -383,7 +407,8 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
|
||||
output_enote_out.enote.onetime_address,
|
||||
output_enote_out.enote.amount_enc,
|
||||
dummy_encrypted_payment_id,
|
||||
output_enote_out.enote.view_tag);
|
||||
output_enote_out.enote.view_tag,
|
||||
return_pubkey_out);
|
||||
|
||||
// 6. make special janus anchor: anchor_sp = H_16(D_e, input_context, Ko, k_v)
|
||||
janus_anchor_t janus_anchor_special;
|
||||
@@ -400,14 +425,100 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
|
||||
// 8. save the enote ephemeral pubkey, first tx key image, and amount
|
||||
output_enote_out.enote.enote_ephemeral_pubkey = enote_ephemeral_pubkey;
|
||||
output_enote_out.enote.tx_first_key_image = tx_first_key_image;
|
||||
output_enote_out.enote.asset_type = "SAL1";
|
||||
output_enote_out.enote.asset_type = proposal.asset_type;
|
||||
output_enote_out.enote.return_enc = crypto::rand<carrot::encrypted_return_pubkey_t>();
|
||||
output_enote_out.amount = proposal.amount;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void get_output_proposal_paymentchannel_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const crypto::public_key &K_o,
|
||||
const uint64_t idx,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out)
|
||||
{
|
||||
// 1. sanity checks
|
||||
CARROT_CHECK_AND_THROW(proposal.randomness != null_anchor,
|
||||
missing_randomness, "invalid randomness for janus anchor (zero).");
|
||||
|
||||
// 2. input context: input_context = "R" || KI_1
|
||||
const input_context_t input_context = make_carrot_input_context(tx_first_key_image);
|
||||
/*
|
||||
// K_v = K_return - k_idx * T
|
||||
CarrotPaymentProposalV1 proposal_with_kv = proposal;
|
||||
const bool is_sparc = (k_idx != crypto::null_skey) && sc_isnonzero(to_bytes(k_idx)); // check here! for zero its not needed
|
||||
if (is_sparc)
|
||||
{
|
||||
// Calculate K_v = K_return - k_idx * T
|
||||
const rct::key K_return_rct = rct::pk2rct(proposal.destination.address_view_pubkey);
|
||||
const rct::key k_idx_T = rct::scalarmultKey(rct::pk2rct(crypto::get_T()), rct::sk2rct(k_idx));
|
||||
rct::key K_v_rct;
|
||||
rct::subKeys(K_v_rct, K_return_rct, k_idx_T);
|
||||
proposal_with_kv.destination.address_view_pubkey = rct::rct2pk(K_v_rct);
|
||||
}
|
||||
*/
|
||||
mx25519_pubkey s_sender_receiver_unctx; auto dhe_wiper = auto_wiper(s_sender_receiver_unctx);
|
||||
get_normal_proposal_ecdh_parts(proposal,
|
||||
input_context,
|
||||
output_enote_out.enote.enote_ephemeral_pubkey,
|
||||
s_sender_receiver_unctx);
|
||||
|
||||
// 4. build the output enote address pieces
|
||||
crypto::hash s_sender_receiver; auto q_wiper = auto_wiper(s_sender_receiver);
|
||||
encrypted_return_pubkey_t return_pubkey;
|
||||
get_external_output_proposal_parts(
|
||||
s_sender_receiver_unctx,
|
||||
proposal.destination.address_spend_pubkey,
|
||||
proposal.destination.payment_id,
|
||||
proposal.amount,
|
||||
CarrotEnoteType::PAYMENT,
|
||||
output_enote_out.enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
s_view_balance_dev,
|
||||
false, // coinbase_amount_commitment
|
||||
s_sender_receiver,
|
||||
output_enote_out.amount_blinding_factor,
|
||||
output_enote_out.enote.amount_commitment,
|
||||
output_enote_out.enote.onetime_address,
|
||||
output_enote_out.enote.amount_enc,
|
||||
encrypted_payment_id_out,
|
||||
output_enote_out.enote.view_tag,
|
||||
return_pubkey
|
||||
);
|
||||
|
||||
// Override the onetime address
|
||||
crypto::secret_key k_idx;
|
||||
make_sparc_return_index(s_sender_receiver_unctx.data, input_context, K_o, idx, k_idx);
|
||||
rct::key K_r = rct::addKeys(rct::pk2rct(proposal.destination.address_spend_pubkey),rct::pk2rct(proposal.destination.address_view_pubkey));
|
||||
rct::key K_idx = rct::scalarmultKey(rct::pk2rct(crypto::get_T()), rct::sk2rct(k_idx));
|
||||
output_enote_out.enote.onetime_address = rct::rct2pk(rct::addKeys(K_r, K_idx));
|
||||
|
||||
// Recalculate the view tag : vt = H_3(s_sr || input_context || Ksra)
|
||||
make_carrot_view_tag(s_sender_receiver_unctx.data, input_context, output_enote_out.enote.onetime_address, output_enote_out.enote.view_tag);
|
||||
|
||||
// Recalculate a_enc = BytesToInt64(a) XOR m_a
|
||||
output_enote_out.enote.amount_enc = encrypt_carrot_amount(proposal.amount, s_sender_receiver, output_enote_out.enote.onetime_address);
|
||||
|
||||
// Recalculate anchor_enc = anchor XOR m_anchor
|
||||
output_enote_out.enote.anchor_enc = encrypt_carrot_anchor(proposal.randomness, s_sender_receiver, output_enote_out.enote.onetime_address);
|
||||
|
||||
// Recalculate the pid_enc = pid XOR m_pid
|
||||
encrypted_payment_id_out = encrypt_legacy_payment_id(proposal.destination.payment_id, s_sender_receiver, output_enote_out.enote.onetime_address);
|
||||
|
||||
// 6. save the amount & first key image & asset type
|
||||
output_enote_out.amount = proposal.amount;
|
||||
output_enote_out.enote.asset_type = proposal.asset_type;
|
||||
output_enote_out.enote.tx_first_key_image = tx_first_key_image;
|
||||
// disable returning an already returned tx.
|
||||
output_enote_out.enote.return_enc = crypto::rand<carrot::encrypted_return_pubkey_t>();
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void get_output_proposal_return_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out)
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out)
|
||||
{
|
||||
// 1. sanity checks
|
||||
CARROT_CHECK_AND_THROW(proposal.randomness != null_anchor,
|
||||
@@ -425,27 +536,30 @@ void get_output_proposal_return_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
|
||||
// 4. build the output enote address pieces
|
||||
crypto::hash s_sender_receiver; auto q_wiper = auto_wiper(s_sender_receiver);
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: the following call needs the "destination" parameter adjusted for return_payment
|
||||
get_external_output_proposal_parts(s_sender_receiver_unctx,
|
||||
proposal.destination.address_spend_pubkey,
|
||||
proposal.destination.payment_id,
|
||||
proposal.amount,
|
||||
CarrotEnoteType::PAYMENT,
|
||||
output_enote_out.enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
false,
|
||||
s_sender_receiver,
|
||||
output_enote_out.amount_blinding_factor,
|
||||
output_enote_out.enote.amount_commitment,
|
||||
output_enote_out.enote.onetime_address,
|
||||
output_enote_out.enote.amount_enc,
|
||||
encrypted_payment_id_out,
|
||||
output_enote_out.enote.view_tag);
|
||||
encrypted_return_pubkey_t return_pubkey;
|
||||
get_external_output_proposal_parts(
|
||||
s_sender_receiver_unctx,
|
||||
proposal.destination.address_spend_pubkey,
|
||||
proposal.destination.payment_id,
|
||||
proposal.amount,
|
||||
CarrotEnoteType::PAYMENT,
|
||||
output_enote_out.enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
s_view_balance_dev,
|
||||
false, // coinbase_amount_commitment
|
||||
s_sender_receiver,
|
||||
output_enote_out.amount_blinding_factor,
|
||||
output_enote_out.enote.amount_commitment,
|
||||
output_enote_out.enote.onetime_address,
|
||||
output_enote_out.enote.amount_enc,
|
||||
encrypted_payment_id_out,
|
||||
output_enote_out.enote.view_tag,
|
||||
return_pubkey
|
||||
);
|
||||
|
||||
// 5. Override the values that change because of the enote onetime address (K_o) changing
|
||||
// i.e. {K_o, vt, m_a, a_enc, m_anchor, anchor_enc, m_pid, pid_enc}
|
||||
|
||||
|
||||
// Override the onetime address
|
||||
output_enote_out.enote.onetime_address = rct::rct2pk(rct::addKeys(rct::pk2rct(proposal.destination.address_spend_pubkey), rct::pk2rct(proposal.destination.address_view_pubkey)));
|
||||
|
||||
@@ -461,15 +575,20 @@ void get_output_proposal_return_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
// Recalculate the pid_enc = pid XOR m_pid
|
||||
encrypted_payment_id_out = encrypt_legacy_payment_id(proposal.destination.payment_id, s_sender_receiver, output_enote_out.enote.onetime_address);
|
||||
|
||||
// 6. save the amount and first key image
|
||||
// 6. save the amount & first key image & asset type
|
||||
output_enote_out.amount = proposal.amount;
|
||||
output_enote_out.enote.asset_type = proposal.asset_type;
|
||||
output_enote_out.enote.tx_first_key_image = tx_first_key_image;
|
||||
// disable returning an already returned tx.
|
||||
output_enote_out.enote.return_enc = crypto::rand<carrot::encrypted_return_pubkey_t>();
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void get_output_proposal_internal_v1(const CarrotPaymentProposalSelfSendV1 &proposal,
|
||||
const view_balance_secret_device &s_view_balance_dev,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const std::optional<mx25519_pubkey> &other_enote_ephemeral_pubkey,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
RCTOutputEnoteProposal &return_enote_out,
|
||||
RCTOutputEnoteProposal &output_enote_out)
|
||||
{
|
||||
// 1. sanity checks
|
||||
@@ -528,8 +647,40 @@ void get_output_proposal_internal_v1(const CarrotPaymentProposalSelfSendV1 &prop
|
||||
// 9. save the enote ephemeral pubkey, first tx key image, and amount
|
||||
output_enote_out.enote.enote_ephemeral_pubkey = enote_ephemeral_pubkey;
|
||||
output_enote_out.enote.tx_first_key_image = tx_first_key_image;
|
||||
output_enote_out.enote.asset_type = "SAL1";
|
||||
output_enote_out.enote.asset_type = proposal.asset_type;
|
||||
output_enote_out.enote.return_enc = crypto::rand<carrot::encrypted_return_pubkey_t>();
|
||||
output_enote_out.amount = proposal.amount;
|
||||
|
||||
// 10. construct the stake return enote
|
||||
if (tx_type == cryptonote::transaction_type::STAKE || tx_type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
// make k_return
|
||||
crypto::secret_key k_return;
|
||||
s_view_balance_dev.make_internal_return_privkey(input_context, output_enote_out.enote.onetime_address, k_return);
|
||||
|
||||
// compute K_return = k_return * G
|
||||
crypto::public_key return_pub;
|
||||
crypto::secret_key_to_public_key(k_return, return_pub);
|
||||
|
||||
// Make a destination address for the return
|
||||
CarrotDestinationV1 return_destination;
|
||||
make_carrot_main_address_v1(output_enote_out.enote.onetime_address, return_pub, return_destination);
|
||||
|
||||
// Create the return proposal, using the return address and the amount
|
||||
const CarrotPaymentProposalV1 proposal_return = CarrotPaymentProposalV1{
|
||||
.destination = return_destination,
|
||||
.amount = 0,
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
encrypted_payment_id_t encrypted_payment_id_return;
|
||||
get_output_proposal_return_v1(
|
||||
proposal_return,
|
||||
tx_first_key_image,
|
||||
nullptr, // s_view_balance_dev
|
||||
return_enote_out,
|
||||
encrypted_payment_id_return
|
||||
);
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
CarrotPaymentProposalV1 gen_carrot_payment_proposal_v1(const bool is_subaddress,
|
||||
|
||||
@@ -82,6 +82,8 @@ struct CarrotPaymentProposalSelfSendV1 final
|
||||
std::optional<mx25519_pubkey> enote_ephemeral_pubkey;
|
||||
/// anchor: arbitrary, pre-encrypted message for _internal_ selfsends
|
||||
std::optional<janus_anchor_t> internal_message;
|
||||
/// asset type
|
||||
std::string asset_type;
|
||||
};
|
||||
|
||||
struct RCTOutputEnoteProposal
|
||||
@@ -133,9 +135,25 @@ void get_coinbase_output_proposal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
*/
|
||||
void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out);
|
||||
/**
|
||||
* brief: get_output_proposal_paymentchannel_v1 - convert the carrot proposal to an output proposal
|
||||
* param: proposal -
|
||||
* param: tx_first_key_image -
|
||||
* param: k_view_dev -
|
||||
* outparam: output_enote_out -
|
||||
* outparam: encrypted_payment_id_out - pid_enc
|
||||
*/
|
||||
void get_output_proposal_paymentchannel_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
const crypto::public_key &K_o,
|
||||
const uint64_t idx,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out);
|
||||
/**
|
||||
* brief: get_output_proposal_return_v1 - convert the carrot proposal to an output proposal
|
||||
* param: proposal -
|
||||
* param: tx_first_key_image -
|
||||
@@ -145,6 +163,7 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
*/
|
||||
void get_output_proposal_return_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const view_balance_secret_device *s_view_balance_dev,
|
||||
RCTOutputEnoteProposal &output_enote_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out);
|
||||
/**
|
||||
@@ -173,6 +192,8 @@ void get_output_proposal_internal_v1(const CarrotPaymentProposalSelfSendV1 &prop
|
||||
const view_balance_secret_device &s_view_balance_dev,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const std::optional<mx25519_pubkey> &other_enote_ephemeral_pubkey,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
RCTOutputEnoteProposal &return_enote_out,
|
||||
RCTOutputEnoteProposal &output_enote_out);
|
||||
/**
|
||||
* brief: gen_jamtis_payment_proposal_v1 - generate a random proposal
|
||||
|
||||
+189
-21
@@ -70,6 +70,104 @@ static crypto::secret_key make_enote_ephemeral_privkey_sender(const janus_anchor
|
||||
return enote_ephemeral_privkey;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool scan_return_output(
|
||||
const crypto::public_key &return_onetime_address,
|
||||
const mx25519_pubkey &return_ephemeral_pubkey,
|
||||
const carrot::view_tag_t &return_view_tag,
|
||||
const carrot::encrypted_janus_anchor_t &return_anchor_enc,
|
||||
const carrot::encrypted_amount_t &return_amount_enc,
|
||||
const std::optional<rct::key> amount_commitment,
|
||||
const carrot::input_context_t &return_input_context,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
crypto::public_key &address_spend_pubkey_out,
|
||||
rct::xmr_amount &amount_out,
|
||||
crypto::secret_key &amount_blinding_factor_out
|
||||
) {
|
||||
const auto &return_output_map = account.get_return_output_map_ref();
|
||||
CHECK_AND_ASSERT_MES(return_output_map.count(return_onetime_address), false, "return output not found");
|
||||
const auto &origin_tx = return_output_map.at(return_onetime_address);
|
||||
|
||||
// 1. make k_return
|
||||
crypto::secret_key k_return;
|
||||
account.s_view_balance_dev.make_internal_return_privkey(origin_tx.input_context, origin_tx.K_o, k_return);
|
||||
|
||||
// 2. compute K_return' = k_return * G
|
||||
crypto::public_key K_return;
|
||||
crypto::secret_key_to_public_key(k_return, K_return);
|
||||
|
||||
// 3. ssr
|
||||
mx25519_pubkey shared_secret_return_unctx;
|
||||
crypto::hash shared_secret_return;
|
||||
carrot::make_carrot_uncontextualized_shared_key_receiver(k_return, return_ephemeral_pubkey, shared_secret_return_unctx);
|
||||
carrot::make_carrot_sender_receiver_secret(
|
||||
shared_secret_return_unctx.data,
|
||||
return_ephemeral_pubkey,
|
||||
return_input_context,
|
||||
shared_secret_return
|
||||
);
|
||||
|
||||
// 4. verify the view_tag
|
||||
CHECK_AND_ASSERT_MES(
|
||||
carrot::test_carrot_view_tag(
|
||||
shared_secret_return_unctx.data,
|
||||
return_input_context,
|
||||
return_onetime_address,
|
||||
return_view_tag
|
||||
),
|
||||
false,
|
||||
"view tag verification failed for carrot coinbase enote"
|
||||
);
|
||||
|
||||
// 5. compute anchor_return
|
||||
carrot::janus_anchor_t recovered_anchor_return =
|
||||
carrot::decrypt_carrot_anchor(return_anchor_enc, shared_secret_return, return_onetime_address);
|
||||
|
||||
// 6. compute d_e'
|
||||
crypto::secret_key recovered_ephemeral_privkey_return;
|
||||
carrot::make_carrot_enote_ephemeral_privkey(
|
||||
recovered_anchor_return,
|
||||
return_input_context,
|
||||
origin_tx.K_change,
|
||||
carrot::null_payment_id,
|
||||
recovered_ephemeral_privkey_return
|
||||
);
|
||||
|
||||
// 7. compute D_e'
|
||||
mx25519_pubkey recovered_ephemeral_pubkey_return;
|
||||
carrot::make_carrot_enote_ephemeral_pubkey(
|
||||
recovered_ephemeral_privkey_return,
|
||||
origin_tx.K_change,
|
||||
false,
|
||||
recovered_ephemeral_pubkey_return
|
||||
);
|
||||
|
||||
// 8. verify the enote ephemeral pubkey
|
||||
CHECK_AND_ASSERT_MES(
|
||||
memcmp(recovered_ephemeral_pubkey_return.data, return_ephemeral_pubkey.data, sizeof(mx25519_pubkey)) == 0,
|
||||
false,
|
||||
"carrot coinbase enote protection verification failed"
|
||||
);
|
||||
|
||||
amount_out = carrot::decrypt_carrot_amount(return_amount_enc, shared_secret_return, return_onetime_address);
|
||||
address_spend_pubkey_out = origin_tx.K_change;
|
||||
|
||||
if (amount_commitment)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(
|
||||
carrot::try_recompute_carrot_amount_commitment(shared_secret_return,
|
||||
amount_out,
|
||||
address_spend_pubkey_out,
|
||||
carrot::CarrotEnoteType::PAYMENT,
|
||||
amount_commitment.value(),
|
||||
amount_blinding_factor_out
|
||||
),
|
||||
false,
|
||||
"failed to recompute carrot amount commitment for return output"
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static bool try_scan_carrot_coinbase_enote_checked(
|
||||
const CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver_unctx,
|
||||
@@ -289,6 +387,11 @@ bool try_scan_carrot_enote_external_sender(const CarrotEnoteV1 &enote,
|
||||
CarrotEnoteType &enote_type_out,
|
||||
const bool check_pid)
|
||||
{
|
||||
epee::span<const crypto::public_key> main_address_spend_pubkeys;
|
||||
if (destination.is_subaddress)
|
||||
main_address_spend_pubkeys = {};
|
||||
else
|
||||
main_address_spend_pubkeys = {&destination.address_spend_pubkey, 1};
|
||||
crypto::public_key recovered_address_spend_pubkey;
|
||||
payment_id_t recovered_payment_id;
|
||||
CarrotEnoteType recovered_enote_type;
|
||||
@@ -297,7 +400,7 @@ bool try_scan_carrot_enote_external_sender(const CarrotEnoteV1 &enote,
|
||||
if (!try_scan_carrot_enote_external_normal_checked(enote,
|
||||
encrypted_payment_id,
|
||||
s_sender_receiver_unctx,
|
||||
{&destination.address_spend_pubkey, 1},
|
||||
main_address_spend_pubkeys,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
recovered_address_spend_pubkey,
|
||||
@@ -361,43 +464,108 @@ bool try_scan_carrot_enote_external_receiver(const CarrotEnoteV1 &enote,
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool try_scan_carrot_enote_internal_receiver(const CarrotEnoteV1 &enote,
|
||||
const view_balance_secret_device &s_view_balance_dev,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
crypto::secret_key &sender_extension_g_out,
|
||||
crypto::secret_key &sender_extension_t_out,
|
||||
crypto::public_key &address_spend_pubkey_out,
|
||||
rct::xmr_amount &amount_out,
|
||||
crypto::secret_key &amount_blinding_factor_out,
|
||||
CarrotEnoteType &enote_type_out,
|
||||
janus_anchor_t &internal_message_out)
|
||||
janus_anchor_t &internal_message_out,
|
||||
crypto::public_key &return_address_out,
|
||||
bool &is_return_out)
|
||||
{
|
||||
// Determine whether this is a full wallet or a watch-only wallet
|
||||
const cryptonote::account_keys &keys = account.get_keys();
|
||||
|
||||
// input_context
|
||||
const input_context_t input_context = make_carrot_input_context(enote.tx_first_key_image);
|
||||
|
||||
// assume that the enote is not a return output
|
||||
is_return_out = false;
|
||||
|
||||
// vt = H_3(s_sr || input_context || Ko)
|
||||
view_tag_t nominal_view_tag;
|
||||
s_view_balance_dev.make_internal_view_tag(input_context, enote.onetime_address, nominal_view_tag);
|
||||
account.s_view_balance_dev.make_internal_view_tag(input_context, enote.onetime_address, nominal_view_tag);
|
||||
|
||||
// test view tag
|
||||
if (nominal_view_tag != enote.view_tag)
|
||||
if (nominal_view_tag == enote.view_tag) {
|
||||
// s^ctx_sr = H_32(s_vb, D_e, input_context)
|
||||
crypto::hash s_sender_receiver;
|
||||
account.s_view_balance_dev.make_internal_sender_receiver_secret(enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
s_sender_receiver);
|
||||
|
||||
if (!try_scan_carrot_enote_internal_burnt(enote,
|
||||
s_sender_receiver,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
address_spend_pubkey_out,
|
||||
amount_out,
|
||||
amount_blinding_factor_out,
|
||||
enote_type_out,
|
||||
internal_message_out))
|
||||
return false;
|
||||
|
||||
// we received a change output
|
||||
// save the Kr = K_change + K_return to out subaddress map
|
||||
for (const auto &output_key : enote.tx_output_keys) {
|
||||
// make k_return
|
||||
crypto::secret_key k_return;
|
||||
const carrot::input_context_t input_context = carrot::make_carrot_input_context(enote.tx_first_key_image);
|
||||
account.s_view_balance_dev.make_internal_return_privkey(input_context, output_key, k_return);
|
||||
|
||||
// compute K_return = k_return * G
|
||||
crypto::public_key K_return;
|
||||
crypto::secret_key_to_public_key(k_return, K_return);
|
||||
|
||||
// compute K_r = K_return + K_o
|
||||
crypto::public_key K_r = rct::rct2pk(rct::addKeys(rct::pk2rct(K_return), rct::pk2rct(enote.onetime_address)));
|
||||
|
||||
// calculate the key image for the return output
|
||||
crypto::secret_key sum_g;
|
||||
sc_add(to_bytes(sum_g), to_bytes(sender_extension_g_out), to_bytes(k_return));
|
||||
crypto::key_image key_image = account.derive_key_image_view_only(address_spend_pubkey_out,
|
||||
sum_g,
|
||||
sender_extension_t_out,
|
||||
K_r
|
||||
);
|
||||
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: test whether this will even work for return_payment detection
|
||||
account.insert_return_output_info({{K_r, {input_context, output_key, enote.onetime_address, address_spend_pubkey_out, key_image, sum_g, sender_extension_t_out}}});
|
||||
//account.insert_return_output_info({{K_r, {input_context, output_key, address_spend_pubkey_out, key_image, sum_g, sender_extension_t_out}}});
|
||||
// LAND AHOY!!!
|
||||
}
|
||||
|
||||
// janus protection checks are not needed for internal scans
|
||||
return true;
|
||||
}
|
||||
|
||||
// check for known return addresses
|
||||
const auto &return_map = account.get_return_output_map_ref();
|
||||
if (return_map.find(enote.onetime_address) == return_map.end())
|
||||
return false;
|
||||
|
||||
// s^ctx_sr = H_32(s_vb, D_e, input_context)
|
||||
crypto::hash s_sender_receiver;
|
||||
s_view_balance_dev.make_internal_sender_receiver_secret(enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
s_sender_receiver);
|
||||
// scan the return output
|
||||
if (!scan_return_output(
|
||||
enote.onetime_address,
|
||||
enote.enote_ephemeral_pubkey,
|
||||
enote.view_tag,
|
||||
enote.anchor_enc,
|
||||
enote.amount_enc,
|
||||
enote.amount_commitment,
|
||||
carrot::make_carrot_input_context(enote.tx_first_key_image),
|
||||
account,
|
||||
address_spend_pubkey_out,
|
||||
amount_out,
|
||||
amount_blinding_factor_out))
|
||||
return false;
|
||||
|
||||
return try_scan_carrot_enote_internal_burnt(enote,
|
||||
s_sender_receiver,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
address_spend_pubkey_out,
|
||||
amount_out,
|
||||
amount_blinding_factor_out,
|
||||
enote_type_out,
|
||||
internal_message_out);
|
||||
|
||||
// janus protection checks are not needed for internal scans
|
||||
// if we come here, we have a return output
|
||||
is_return_out = true;
|
||||
return_address_out = enote.onetime_address;
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
} //namespace carrot
|
||||
|
||||
+19
-2
@@ -39,6 +39,7 @@
|
||||
#include "carrot_enote_types.h"
|
||||
#include "device.h"
|
||||
#include "span.h"
|
||||
#include "account.h"
|
||||
|
||||
//third party headers
|
||||
|
||||
@@ -178,14 +179,30 @@ bool try_scan_carrot_enote_external_receiver(const CarrotEnoteV1 &enote,
|
||||
* return: true iff the scan process succeeded
|
||||
*/
|
||||
bool try_scan_carrot_enote_internal_receiver(const CarrotEnoteV1 &enote,
|
||||
const view_balance_secret_device &s_view_balance_dev,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
crypto::secret_key &sender_extension_g_out,
|
||||
crypto::secret_key &sender_extension_t_out,
|
||||
crypto::public_key &address_spend_pubkey_out,
|
||||
rct::xmr_amount &amount_out,
|
||||
crypto::secret_key &amount_blinding_factor_out,
|
||||
CarrotEnoteType &enote_type_out,
|
||||
janus_anchor_t &internal_message_out);
|
||||
janus_anchor_t &internal_message_out,
|
||||
crypto::public_key &return_address_out,
|
||||
bool &is_return_out);
|
||||
//! @TODO: try_scan_carrot_enote_internal_sender(): can't validate burning w/o passing s_sr = s_vb
|
||||
|
||||
bool scan_return_output(
|
||||
const crypto::public_key &return_onetime_address,
|
||||
const mx25519_pubkey &return_ephemeral_pubkey,
|
||||
const carrot::view_tag_t &return_view_tag,
|
||||
const carrot::encrypted_janus_anchor_t &return_anchor_enc,
|
||||
const carrot::encrypted_amount_t &return_amount_enc,
|
||||
const std::optional<rct::key> amount_commitment,
|
||||
const carrot::input_context_t &return_input_context,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
crypto::public_key &address_spend_pubkey_out,
|
||||
rct::xmr_amount &amount_out,
|
||||
crypto::secret_key &amount_blinding_factor_out
|
||||
);
|
||||
|
||||
} //namespace carrot
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
set(carrot_impl_sources
|
||||
account.cpp
|
||||
address_device_ram_borrowed.cpp
|
||||
address_utils_compat.cpp
|
||||
format_utils.cpp
|
||||
|
||||
@@ -1,320 +0,0 @@
|
||||
// Copyright (c) 2014-2022, The Monero Project
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification, are
|
||||
// permitted provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||
// conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||
// of conditions and the following disclaimer in the documentation and/or other
|
||||
// materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without specific
|
||||
// prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "account.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/generators.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "crypto/keccak.h"
|
||||
}
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "ringct/rctOps.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "carrot_impl_account"
|
||||
|
||||
using namespace std;
|
||||
|
||||
DISABLE_VS_WARNINGS(4244 4345)
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
CarrotDestinationV1 carrot_and_legacy_account::cryptonote_address(const payment_id_t payment_id,
|
||||
const AddressDeriveType derive_type) const
|
||||
{
|
||||
CarrotDestinationV1 addr;
|
||||
switch (resolve_derive_type(derive_type))
|
||||
{
|
||||
case AddressDeriveType::Carrot:
|
||||
make_carrot_integrated_address_v1(carrot_account_spend_pubkey,
|
||||
legacy_acb.get_keys().m_account_address.m_view_public_key,
|
||||
payment_id,
|
||||
addr);
|
||||
break;
|
||||
case AddressDeriveType::PreCarrot:
|
||||
make_carrot_integrated_address_v1(legacy_acb.get_keys().m_account_address.m_spend_public_key,
|
||||
legacy_acb.get_keys().m_account_address.m_view_public_key,
|
||||
payment_id,
|
||||
addr);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("address derive type not recognized");
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
CarrotDestinationV1 carrot_and_legacy_account::subaddress(const subaddress_index_extended &subaddress_index) const
|
||||
{
|
||||
if (!subaddress_index.index.is_subaddress())
|
||||
return cryptonote_address(null_payment_id, subaddress_index.derive_type);
|
||||
|
||||
const cryptonote::account_keys &lkeys = legacy_acb.get_keys();
|
||||
|
||||
CarrotDestinationV1 addr;
|
||||
cryptonote::account_public_address cnaddr;
|
||||
switch (resolve_derive_type(subaddress_index.derive_type))
|
||||
{
|
||||
case AddressDeriveType::Carrot:
|
||||
make_carrot_subaddress_v1(carrot_account_spend_pubkey,
|
||||
carrot_account_view_pubkey,
|
||||
s_generate_address_dev,
|
||||
subaddress_index.index.major,
|
||||
subaddress_index.index.minor,
|
||||
addr);
|
||||
break;
|
||||
case AddressDeriveType::PreCarrot:
|
||||
cnaddr =
|
||||
lkeys.m_device->get_subaddress(lkeys, {subaddress_index.index.major, subaddress_index.index.minor});
|
||||
addr = CarrotDestinationV1{
|
||||
.address_spend_pubkey = cnaddr.m_spend_public_key,
|
||||
.address_view_pubkey = cnaddr.m_view_public_key,
|
||||
.is_subaddress = true,
|
||||
.payment_id = null_payment_id
|
||||
};
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("address derive type not recognized");
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> carrot_and_legacy_account::subaddress_map_cn() const
|
||||
{
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> res;
|
||||
for (const auto &p : subaddress_map)
|
||||
if (p.second.derive_type == AddressDeriveType::PreCarrot)
|
||||
res.emplace(p.first, cryptonote::subaddress_index{p.second.index.major, p.second.index.minor});
|
||||
CHECK_AND_ASSERT_THROW_MES(!res.empty(),
|
||||
"carrot_and_legacy_account::subaddress_map_cn: subaddress map does not contain pre-carrot subaddresses");
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::opening_for_subaddress(const subaddress_index_extended &subaddress_index,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
crypto::secret_key &address_privkey_t_out,
|
||||
crypto::public_key &address_spend_pubkey_out) const
|
||||
{
|
||||
const bool is_subaddress = subaddress_index.index.is_subaddress();
|
||||
const uint32_t major_index = subaddress_index.index.major;
|
||||
const uint32_t minor_index = subaddress_index.index.minor;
|
||||
|
||||
const cryptonote::account_keys &lkeys = legacy_acb.get_keys();
|
||||
|
||||
crypto::secret_key address_index_generator;
|
||||
crypto::secret_key subaddress_scalar;
|
||||
crypto::secret_key subaddress_extension;
|
||||
|
||||
switch (resolve_derive_type(subaddress_index.derive_type))
|
||||
{
|
||||
case AddressDeriveType::Carrot:
|
||||
// s^j_gen = H_32[s_ga](j_major, j_minor)
|
||||
make_carrot_index_extension_generator(s_generate_address, major_index, minor_index, address_index_generator);
|
||||
|
||||
if (is_subaddress)
|
||||
{
|
||||
// k^j_subscal = H_n(K_s, j_major, j_minor, s^j_gen)
|
||||
make_carrot_subaddress_scalar(carrot_account_spend_pubkey, address_index_generator, major_index, minor_index, subaddress_scalar);
|
||||
}
|
||||
else
|
||||
{
|
||||
// k^j_subscal = 1
|
||||
sc_1(to_bytes(subaddress_scalar));
|
||||
}
|
||||
|
||||
// k^g_a = k_gi * k^j_subscal
|
||||
sc_mul(to_bytes(address_privkey_g_out), to_bytes(k_generate_image), to_bytes(subaddress_scalar));
|
||||
|
||||
// k^t_a = k_ps * k^j_subscal
|
||||
sc_mul(to_bytes(address_privkey_t_out), to_bytes(k_prove_spend), to_bytes(subaddress_scalar));
|
||||
break;
|
||||
case AddressDeriveType::PreCarrot:
|
||||
// m = Hn(k_v || j_major || j_minor) if subaddress else 0
|
||||
subaddress_extension = is_subaddress
|
||||
? lkeys.get_device().get_subaddress_secret_key(lkeys.m_view_secret_key, {major_index, minor_index})
|
||||
: crypto::null_skey;
|
||||
|
||||
// k^g_a = k_s + m
|
||||
sc_add(to_bytes(address_privkey_g_out), to_bytes(lkeys.m_spend_secret_key), to_bytes(subaddress_extension));
|
||||
|
||||
// k^t_a = 0
|
||||
memset(address_privkey_t_out.data, 0, sizeof(address_privkey_t_out));
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("address derive type not recognized");
|
||||
}
|
||||
|
||||
// perform sanity check
|
||||
const CarrotDestinationV1 addr = subaddress(subaddress_index);
|
||||
rct::key recomputed_address_spend_pubkey;
|
||||
rct::addKeys2(recomputed_address_spend_pubkey,
|
||||
rct::sk2rct(address_privkey_g_out),
|
||||
rct::sk2rct(address_privkey_t_out),
|
||||
rct::pk2rct(crypto::get_T()));
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::rct2pk(recomputed_address_spend_pubkey) == addr.address_spend_pubkey,
|
||||
"carrot and legacy account: opening for subaddress: failed sanity check");
|
||||
address_spend_pubkey_out = addr.address_spend_pubkey;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
bool carrot_and_legacy_account::try_searching_for_opening_for_subaddress(const crypto::public_key &address_spend_pubkey,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
crypto::secret_key &address_privkey_t_out) const
|
||||
{
|
||||
const auto it = subaddress_map.find(address_spend_pubkey);
|
||||
if (it == subaddress_map.cend())
|
||||
return false;
|
||||
|
||||
crypto::public_key recomputed_address_spend_pubkey;
|
||||
opening_for_subaddress(it->second,
|
||||
address_privkey_g_out,
|
||||
address_privkey_t_out,
|
||||
recomputed_address_spend_pubkey);
|
||||
|
||||
return address_spend_pubkey == recomputed_address_spend_pubkey;
|
||||
}
|
||||
bool carrot_and_legacy_account::try_searching_for_opening_for_onetime_address(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
crypto::secret_key &x_out,
|
||||
crypto::secret_key &y_out) const
|
||||
{
|
||||
// k^{j,g}_addr, k^{j,t}_addr
|
||||
crypto::secret_key address_privkey_g;
|
||||
crypto::secret_key address_privkey_t;
|
||||
if (!try_searching_for_opening_for_subaddress(address_spend_pubkey,
|
||||
address_privkey_g,
|
||||
address_privkey_t))
|
||||
return false;
|
||||
|
||||
// x = k^{j,g}_addr + k^g_o
|
||||
sc_add(to_bytes(x_out), to_bytes(address_privkey_g), to_bytes(sender_extension_g));
|
||||
|
||||
// y = k^{j,t}_addr + k^t_o
|
||||
sc_add(to_bytes(y_out), to_bytes(address_privkey_t), to_bytes(sender_extension_t));
|
||||
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
bool carrot_and_legacy_account::can_open_fcmp_onetime_address(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const
|
||||
{
|
||||
crypto::secret_key x, y;
|
||||
if (!try_searching_for_opening_for_onetime_address(address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
x,
|
||||
y))
|
||||
return false;
|
||||
|
||||
// O' = x G + y T
|
||||
rct::key recomputed_onetime_address;
|
||||
rct::addKeys2(recomputed_onetime_address,
|
||||
rct::sk2rct(x),
|
||||
rct::sk2rct(y),
|
||||
rct::pk2rct(crypto::get_T()));
|
||||
|
||||
// O' ?= O
|
||||
return 0 == memcmp(&recomputed_onetime_address, &onetime_address, sizeof(rct::key));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
crypto::key_image carrot_and_legacy_account::derive_key_image(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(can_open_fcmp_onetime_address(
|
||||
address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
onetime_address),
|
||||
"carrot and legacy account: derive key image: cannot open onetime address");
|
||||
|
||||
crypto::secret_key x, y;
|
||||
try_searching_for_opening_for_onetime_address(address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
x,
|
||||
y);
|
||||
|
||||
crypto::key_image L;
|
||||
crypto::generate_key_image(onetime_address, x, L);
|
||||
return L;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::generate_subaddress_map()
|
||||
{
|
||||
const std::vector<AddressDeriveType> derive_types{AddressDeriveType::Carrot, AddressDeriveType::PreCarrot};
|
||||
|
||||
for (uint32_t major_index = 0; major_index <= MAX_SUBADDRESS_MAJOR_INDEX; ++major_index)
|
||||
{
|
||||
for (uint32_t minor_index = 0; minor_index <= MAX_SUBADDRESS_MINOR_INDEX; ++minor_index)
|
||||
{
|
||||
for (const AddressDeriveType derive_type : derive_types)
|
||||
{
|
||||
const subaddress_index_extended subaddr_index{{major_index, minor_index}, derive_type};
|
||||
const CarrotDestinationV1 addr = subaddress(subaddr_index);
|
||||
subaddress_map.insert({addr.address_spend_pubkey, subaddr_index});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::generate(const AddressDeriveType default_derive_type)
|
||||
{
|
||||
//legacy_acb.generate();
|
||||
|
||||
//crypto::generate_random_bytes_thread_safe(sizeof(crypto::secret_key), to_bytes(s_master));
|
||||
s_master = legacy_acb.get_keys().m_spend_secret_key;
|
||||
make_carrot_provespend_key(s_master, k_prove_spend);
|
||||
make_carrot_viewbalance_secret(s_master, s_view_balance);
|
||||
make_carrot_generateimage_key(s_view_balance, k_generate_image);
|
||||
make_carrot_generateaddress_secret(s_view_balance, s_generate_address);
|
||||
|
||||
make_carrot_spend_pubkey(k_generate_image, k_prove_spend, carrot_account_spend_pubkey);
|
||||
k_view_incoming_dev.view_key_scalar_mult_ed25519(carrot_account_spend_pubkey,
|
||||
carrot_account_view_pubkey);
|
||||
|
||||
this->default_derive_type = default_derive_type;
|
||||
|
||||
generate_subaddress_map();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
AddressDeriveType carrot_and_legacy_account::resolve_derive_type(const AddressDeriveType derive_type) const
|
||||
{
|
||||
return derive_type == AddressDeriveType::Auto ? default_derive_type : derive_type;
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -1,117 +0,0 @@
|
||||
// Copyright (c) 2025, 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 "carrot_core/account_secrets.h"
|
||||
#include "carrot_core/address_utils.h"
|
||||
#include "carrot_core/destination.h"
|
||||
#include "carrot_core/device_ram_borrowed.h"
|
||||
#include "carrot_core/enote_utils.h"
|
||||
#include "carrot_impl/subaddress_index.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_basic/subaddress_index.h"
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
static constexpr std::uint32_t MAX_SUBADDRESS_MAJOR_INDEX = 5;
|
||||
static constexpr std::uint32_t MAX_SUBADDRESS_MINOR_INDEX = 20;
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
struct carrot_and_legacy_account
|
||||
{
|
||||
cryptonote::account_base legacy_acb;
|
||||
|
||||
crypto::secret_key s_master;
|
||||
crypto::secret_key k_prove_spend;
|
||||
crypto::secret_key s_view_balance;
|
||||
crypto::secret_key k_generate_image;
|
||||
crypto::secret_key s_generate_address;
|
||||
|
||||
crypto::public_key carrot_account_spend_pubkey;
|
||||
crypto::public_key carrot_account_view_pubkey;
|
||||
|
||||
view_incoming_key_ram_borrowed_device k_view_incoming_dev;
|
||||
view_balance_secret_ram_borrowed_device s_view_balance_dev;
|
||||
generate_address_secret_ram_borrowed_device s_generate_address_dev;
|
||||
|
||||
std::unordered_map<crypto::public_key, subaddress_index_extended> subaddress_map;
|
||||
|
||||
AddressDeriveType default_derive_type;
|
||||
|
||||
carrot_and_legacy_account(): k_view_incoming_dev(legacy_acb.get_keys().m_view_secret_key),
|
||||
s_view_balance_dev(s_view_balance),
|
||||
s_generate_address_dev(s_generate_address)
|
||||
{}
|
||||
|
||||
carrot_and_legacy_account(const carrot_and_legacy_account &k) = delete;
|
||||
carrot_and_legacy_account(carrot_and_legacy_account&&) = delete;
|
||||
|
||||
carrot_and_legacy_account& operator=(const carrot_and_legacy_account&) = delete;
|
||||
carrot_and_legacy_account& operator=(carrot_and_legacy_account&&) = delete;
|
||||
|
||||
CarrotDestinationV1 cryptonote_address(const payment_id_t payment_id = null_payment_id,
|
||||
const AddressDeriveType derive_type = AddressDeriveType::Auto) const;
|
||||
|
||||
CarrotDestinationV1 subaddress(const subaddress_index_extended &subaddress_index) const;
|
||||
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddress_map_cn() const;
|
||||
|
||||
// brief: opening_for_subaddress - return (k^g_a, k^t_a) for j s.t. K^j_s = (k^g_a * G + k^t_a * T)
|
||||
void opening_for_subaddress(const subaddress_index_extended &subaddress_index,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
crypto::secret_key &address_privkey_t_out,
|
||||
crypto::public_key &address_spend_pubkey_out) const;
|
||||
|
||||
bool try_searching_for_opening_for_subaddress(const crypto::public_key &address_spend_pubkey,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
crypto::secret_key &address_privkey_t_out) const;
|
||||
|
||||
bool try_searching_for_opening_for_onetime_address(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
crypto::secret_key &x_out,
|
||||
crypto::secret_key &y_out) const;
|
||||
|
||||
bool can_open_fcmp_onetime_address(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const;
|
||||
|
||||
crypto::key_image derive_key_image(const crypto::public_key &address_spend_pubkey,
|
||||
const crypto::secret_key &sender_extension_g,
|
||||
const crypto::secret_key &sender_extension_t,
|
||||
const crypto::public_key &onetime_address) const;
|
||||
|
||||
void generate_subaddress_map();
|
||||
|
||||
void generate(const AddressDeriveType default_derive_type = AddressDeriveType::Carrot);
|
||||
|
||||
AddressDeriveType resolve_derive_type(const AddressDeriveType derive_type) const;
|
||||
};
|
||||
}
|
||||
@@ -86,6 +86,12 @@ inline void serialize(Archive &a, carrot::encrypted_return_pubkey_t &x, const bo
|
||||
}
|
||||
//---------------------------------------------------
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, carrot::rollup_binding_tag_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.bytes;
|
||||
}
|
||||
//---------------------------------------------------
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, carrot::CarrotDestinationV1 &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.address_spend_pubkey;
|
||||
|
||||
@@ -42,3 +42,4 @@ BLOB_SERIALIZER(carrot::view_tag_t);
|
||||
BLOB_SERIALIZER(carrot::encrypted_janus_anchor_t);
|
||||
BLOB_SERIALIZER(carrot::encrypted_payment_id_t);
|
||||
BLOB_SERIALIZER(carrot::encrypted_return_pubkey_t);
|
||||
BLOB_SERIALIZER(carrot::rollup_binding_tag_t);
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "carrot_core/enote_utils.h"
|
||||
#include "carrot_core/exceptions.h"
|
||||
#include "carrot_core/payment_proposal.h"
|
||||
#include "common/container_helpers.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/cryptonote_tx_utils.h"
|
||||
#include "cryptonote_config.h"
|
||||
@@ -59,10 +58,10 @@ static void store_carrot_ephemeral_pubkeys_to_extra(const EnoteContainer &enotes
|
||||
if (nouts == 0)
|
||||
return;
|
||||
|
||||
const bool use_shared_ephemeral_pubkey = nouts == 2 && 0 == memcmp(
|
||||
const bool use_shared_ephemeral_pubkey = nouts == 1 || (nouts == 2 && 0 == memcmp(
|
||||
&enotes.front().enote_ephemeral_pubkey,
|
||||
&enotes.back().enote_ephemeral_pubkey,
|
||||
sizeof(mx25519_pubkey));
|
||||
sizeof(mx25519_pubkey)));
|
||||
bool success = true;
|
||||
if (use_shared_ephemeral_pubkey)
|
||||
{
|
||||
@@ -194,21 +193,55 @@ bool try_load_carrot_extra_v1(
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotEnoteV1> &enotes,
|
||||
const std::vector<crypto::key_image> &key_images,
|
||||
const std::vector<cryptonote::tx_source_entry> &sources,
|
||||
const rct::xmr_amount fee,
|
||||
const encrypted_payment_id_t encrypted_payment_id)
|
||||
const std::vector<crypto::key_image> &key_images,
|
||||
const std::vector<cryptonote::tx_source_entry> &sources,
|
||||
const rct::xmr_amount fee,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const rct::xmr_amount tx_amount_burnt,
|
||||
const std::vector<uint8_t> &change_masks,
|
||||
const cryptonote::token_metadata_t &token,
|
||||
const carrot::RCTOutputEnoteProposal &return_enote,
|
||||
const encrypted_payment_id_t encrypted_payment_id,
|
||||
const uint8_t hf_version)
|
||||
{
|
||||
const size_t nins = key_images.size();
|
||||
const size_t nouts = enotes.size();
|
||||
CHECK_AND_ASSERT_THROW_MES(nins == sources.size(), "invalid inputs/sources size");
|
||||
CHECK_AND_ASSERT_THROW_MES(change_masks.size() == nouts, "invalid change masks size. Expected: " << nouts - 1 << " got: " << change_masks.size());
|
||||
|
||||
// Sanity check asset types - all enotes and sources must be the same
|
||||
std::string asset_type = "";
|
||||
for (const auto &enote: enotes) {
|
||||
if (asset_type == "")
|
||||
asset_type = enote.asset_type;
|
||||
else
|
||||
CHECK_AND_ASSERT_THROW_MES(enote.asset_type == asset_type, "invalid asset_type in enote. Expected: " << asset_type << " got: " << enote.asset_type);
|
||||
}
|
||||
for (const auto &source: sources) {
|
||||
if (asset_type == "")
|
||||
asset_type = source.asset_type;
|
||||
else
|
||||
CHECK_AND_ASSERT_THROW_MES(source.asset_type == asset_type, "invalid asset_type in source. Expected: " << asset_type << " got: " << source.asset_type);
|
||||
}
|
||||
|
||||
cryptonote::transaction tx;
|
||||
tx.pruned = true;
|
||||
tx.version = 2;
|
||||
tx.unlock_time = 0;
|
||||
tx.source_asset_type = asset_type;
|
||||
tx.destination_asset_type = asset_type;
|
||||
tx.version = (hf_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : TRANSACTION_VERSION_CARROT;
|
||||
tx.type =
|
||||
tx_type == cryptonote::transaction_type::RETURN ? cryptonote::transaction_type::TRANSFER : tx_type;
|
||||
tx.amount_burnt = (
|
||||
tx.type == cryptonote::transaction_type::STAKE ||
|
||||
tx.type == cryptonote::transaction_type::BURN ||
|
||||
tx.type == cryptonote::transaction_type::CREATE_TOKEN ||
|
||||
tx.type == cryptonote::transaction_type::ROLLUP
|
||||
) ? tx_amount_burnt : 0;
|
||||
tx.return_address_change_mask.assign(change_masks.begin(), change_masks.end());
|
||||
tx.vin.reserve(nins);
|
||||
tx.vout.reserve(nouts);
|
||||
tx.return_address_list.reserve(change_masks.size());
|
||||
tx.extra.reserve(MAX_TX_EXTRA_SIZE);
|
||||
tx.rct_signatures.type = carrot_v1_rct_type;
|
||||
tx.rct_signatures.txnFee = fee;
|
||||
@@ -226,7 +259,7 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
//L
|
||||
tx.vin.emplace_back(cryptonote::txin_to_key{ //@TODO: can save 2 bytes by using slim input type
|
||||
.amount = 0,
|
||||
.asset_type = "SAL1",
|
||||
.asset_type = asset_type,
|
||||
.key_offsets = cryptonote::absolute_output_offsets_to_relative(key_offsets),
|
||||
.k_image = key_images.at(i)
|
||||
});
|
||||
@@ -244,13 +277,35 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
}});
|
||||
|
||||
//a_enc
|
||||
rct::ecdhTuple &ecdh_tuple = tools::add_element(tx.rct_signatures.ecdhInfo);
|
||||
rct::ecdhTuple &ecdh_tuple = tx.rct_signatures.ecdhInfo.emplace_back();
|
||||
memcpy(ecdh_tuple.amount.bytes, enote.amount_enc.bytes, sizeof(ecdh_tuple.amount));
|
||||
|
||||
//C_a
|
||||
tx.rct_signatures.outPk.push_back(rct::ctkey{rct::key{}, enote.amount_commitment});
|
||||
|
||||
//K_return
|
||||
if (tx_type != cryptonote::transaction_type::STAKE && tx_type != cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
crypto::public_key K_return;
|
||||
memcpy(K_return.data, enote.return_enc.bytes, sizeof(crypto::public_key));
|
||||
tx.return_address_list.push_back(K_return);
|
||||
}
|
||||
}
|
||||
|
||||
// store the return pubkey for stake txs
|
||||
if (tx_type == cryptonote::transaction_type::STAKE || tx_type == cryptonote::transaction_type::CREATE_TOKEN)
|
||||
{
|
||||
tx.protocol_tx_data.version = 1;
|
||||
memcpy(tx.protocol_tx_data.return_address.data, return_enote.enote.onetime_address.data, sizeof(crypto::public_key));
|
||||
memcpy(tx.protocol_tx_data.return_pubkey.data, return_enote.enote.enote_ephemeral_pubkey.data, sizeof(crypto::public_key));
|
||||
tx.protocol_tx_data.return_view_tag = return_enote.enote.view_tag;
|
||||
tx.protocol_tx_data.return_anchor_enc = return_enote.enote.anchor_enc;
|
||||
}
|
||||
if (tx_type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
tx.token_metadata = token;
|
||||
} else {
|
||||
tx.token_metadata = cryptonote::token_metadata_t{};
|
||||
}
|
||||
|
||||
//ephemeral pubkeys: D_e
|
||||
store_carrot_ephemeral_pubkeys_to_extra(enotes, tx.extra);
|
||||
|
||||
@@ -324,6 +379,14 @@ bool try_load_carrot_enote_from_transaction_v1(const cryptonote::transaction &tx
|
||||
|
||||
//D_e
|
||||
enote_out.enote_ephemeral_pubkey = enote_ephemeral_pubkeys[ephemeral_pubkey_index];
|
||||
|
||||
// save all output keys in order to calculate Kr values.
|
||||
for (const auto& out: tx.vout) {
|
||||
const cryptonote::txout_to_carrot_v1 * const carrot_out = boost::strict_get<cryptonote::txout_to_carrot_v1>(&out.target);
|
||||
if (carrot_out) {
|
||||
enote_out.tx_output_keys.push_back(carrot_out->key);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -382,7 +445,7 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1(
|
||||
cryptonote::transaction tx;
|
||||
tx.type = tx_type;
|
||||
tx.pruned = false;
|
||||
tx.version = 2;
|
||||
tx.version = TRANSACTION_VERSION_CARROT;
|
||||
tx.unlock_time = CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
tx.vin.reserve(1);
|
||||
tx.vout.reserve(nouts);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/tx_extra.h"
|
||||
#include "cryptonote_core/cryptonote_tx_utils.h"
|
||||
#include "carrot_core/payment_proposal.h"
|
||||
|
||||
//third party headers
|
||||
|
||||
@@ -101,10 +102,16 @@ bool try_load_carrot_extra_v1(
|
||||
* return: a fully populated, pruned, non-coinbase transaction containing given Carrot information
|
||||
*/
|
||||
cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotEnoteV1> &enotes,
|
||||
const std::vector<crypto::key_image> &key_images,
|
||||
const std::vector<cryptonote::tx_source_entry> &sources,
|
||||
const rct::xmr_amount fee,
|
||||
const encrypted_payment_id_t encrypted_payment_id);
|
||||
const std::vector<crypto::key_image> &key_images,
|
||||
const std::vector<cryptonote::tx_source_entry> &sources,
|
||||
const rct::xmr_amount fee,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const rct::xmr_amount tx_amount_burnt,
|
||||
const std::vector<uint8_t> &change_masks,
|
||||
const cryptonote::token_metadata_t &token,
|
||||
const RCTOutputEnoteProposal &return_enote,
|
||||
const encrypted_payment_id_t encrypted_payment_id,
|
||||
const uint8_t hf_version);
|
||||
/**
|
||||
* brief: try_load_carrot_enote_from_transaction_v1 - load one non-coinbase Carrot enote from a cryptonote::transaction
|
||||
* param: tx -
|
||||
|
||||
@@ -88,7 +88,8 @@ static std::pair<std::size_t, boost::multiprecision::uint128_t> input_count_for_
|
||||
const epee::span<const InputCandidate> input_candidates,
|
||||
const std::set<std::size_t> &selectable_inputs,
|
||||
std::size_t max_num_input_count,
|
||||
const std::map<std::size_t, rct::xmr_amount> &fee_by_input_count)
|
||||
const std::map<std::size_t, rct::xmr_amount> &fee_by_input_count,
|
||||
const bool is_token_transfer)
|
||||
{
|
||||
// Returns (N, X) where the X is the sum of the amounts of the greatest N <= max_num_input_count
|
||||
// inputs from selectable_inputs, maximizing X - F(N). F(N) is the fee for this transaction,
|
||||
@@ -96,6 +97,7 @@ static std::pair<std::size_t, boost::multiprecision::uint128_t> input_count_for_
|
||||
// the fee, but greater than or equal to the difference of the fee compared to excluding that
|
||||
// input. If this function returns N == 0, then there aren't enough usable funds, i.e. no N
|
||||
// exists such that X - F(N) > 0.
|
||||
// For token transfers, fee is paid separately in SAL1 so we just accumulate all inputs.
|
||||
|
||||
if (fee_by_input_count.empty() || selectable_inputs.empty())
|
||||
return {0, 0};
|
||||
@@ -125,6 +127,15 @@ static std::pair<std::size_t, boost::multiprecision::uint128_t> input_count_for_
|
||||
{
|
||||
const rct::xmr_amount amount = *amount_it;
|
||||
const rct::xmr_amount current_fee = fee_by_input_count.at(num_ins + 1);
|
||||
|
||||
// For token transfers, fee is paid separately in SAL1 - just accumulate inputs
|
||||
if (is_token_transfer)
|
||||
{
|
||||
++num_ins;
|
||||
cumulative_input_sum += amount;
|
||||
continue;
|
||||
}
|
||||
|
||||
CARROT_CHECK_AND_THROW(current_fee > last_fee,
|
||||
carrot_logic_error, "provided fee by input count is not monotonically increasing");
|
||||
const rct::xmr_amount marginal_fee_diff = current_fee - last_fee;
|
||||
@@ -318,23 +329,27 @@ std::vector<std::size_t> get_input_counts_in_preferred_order()
|
||||
// 1 or 2 randomly, then
|
||||
// other ascending powers of 2, then
|
||||
// other ascending positive numbers
|
||||
|
||||
|
||||
//! @TODO: MRL discussion about 2 vs 1 default input count when 1 input can pay. If we default
|
||||
// to 1, then that may reveal more information about the amount, and reveals that one can't pay
|
||||
// with 1 output when using 2. Vice versa, if we default to 2, then that means that one only
|
||||
// owns 1 output when using 1. It may be the most advantageous to randomly switch between
|
||||
// preferring 1 vs 2. See: https://lavalle.pl/planning/node437.html. Con to this approach: if we
|
||||
// default to 1 over 2 always then there's scenarios where we net save tx fees and proving time.
|
||||
|
||||
static_assert(CARROT_MAX_TX_INPUTS == FCMP_PLUS_PLUS_MAX_INPUTS, "inconsistent input count max limit");
|
||||
static_assert(CARROT_MIN_TX_INPUTS == 1 && CARROT_MAX_TX_INPUTS == 8,
|
||||
// preferring 1 vs 2. See: https://lavalle.pl/planning/node437.html. Con to this approach: if we
|
||||
// default to 1 over 2 always then there's scenarios where we net save tx fees and proving time.
|
||||
|
||||
//static_assert(CARROT_MAX_TX_INPUTS == FCMP_PLUS_PLUS_MAX_INPUTS, "inconsistent input count max limit");
|
||||
static_assert(CARROT_MIN_TX_INPUTS == 1 && CARROT_MAX_TX_INPUTS == 64,
|
||||
"refactor this function for different input count limits");
|
||||
|
||||
const bool random_bit = 0 == (crypto::rand<uint8_t>() & 0x01);
|
||||
if (random_bit)
|
||||
return {2, 1, 4, 8, 3, 5, 6, 7};
|
||||
return {2, 1, 4, 8, 16, 32, 64, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
|
||||
else
|
||||
return {1, 2, 4, 8, 3, 5, 6, 7};
|
||||
return {1, 2, 4, 8, 16, 32, 64, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
select_inputs_func_t make_single_transfer_input_selector(
|
||||
@@ -368,11 +383,12 @@ select_inputs_func_t make_single_transfer_input_selector(
|
||||
|
||||
// 3. Calculate minimum required input money sum for a given input count
|
||||
const bool subtract_fee = flags & IS_KNOWN_FEE_SUBTRACTABLE;
|
||||
const bool is_token_transfer = flags & IS_TOKEN_TRANSFER;
|
||||
std::map<std::size_t, boost::multiprecision::uint128_t> required_money_by_input_count;
|
||||
for (const auto &fee_and_input_count : fee_by_input_count)
|
||||
{
|
||||
required_money_by_input_count[fee_and_input_count.first] =
|
||||
nominal_output_sum + (subtract_fee ? 0 : fee_and_input_count.second);
|
||||
nominal_output_sum + ((subtract_fee || is_token_transfer) ? 0 : fee_and_input_count.second);
|
||||
}
|
||||
const boost::multiprecision::uint128_t absolute_minimum_required_money
|
||||
= required_money_by_input_count.cbegin()->second;
|
||||
@@ -386,9 +402,10 @@ select_inputs_func_t make_single_transfer_input_selector(
|
||||
"Not enough money in all inputs (" << cryptonote::print_money(total_candidate_money)
|
||||
<< ") to fund minimum output sum (" << cryptonote::print_money(absolute_minimum_required_money) << ')');
|
||||
|
||||
// const bool is_token_transfer = flags & IS_TOKEN_TRANSFER;
|
||||
std::set<std::size_t> all_idxs; for (std::size_t i = 0; i < input_candidates.size(); ++i) all_idxs.insert(i);
|
||||
const std::pair<std::size_t, boost::multiprecision::uint128_t> max_usable_money =
|
||||
input_count_for_max_usable_money(input_candidates, all_idxs, FCMP_PLUS_PLUS_MAX_INPUTS, fee_by_input_count);
|
||||
input_count_for_max_usable_money(input_candidates, all_idxs, CARROT_MAX_TX_INPUTS, fee_by_input_count, is_token_transfer);
|
||||
CARROT_CHECK_AND_THROW(max_usable_money.second >= absolute_minimum_required_money,
|
||||
not_enough_usable_money,
|
||||
"Not enough usable money in top " << max_usable_money.first << " inputs ("
|
||||
@@ -413,7 +430,7 @@ select_inputs_func_t make_single_transfer_input_selector(
|
||||
|
||||
// Skip if not enough money in this selectable set for max number of tx inputs...
|
||||
const auto max_usable_money = input_count_for_max_usable_money(input_candidates,
|
||||
input_candidate_subset, FCMP_PLUS_PLUS_MAX_INPUTS, fee_by_input_count);
|
||||
input_candidate_subset, CARROT_MAX_TX_INPUTS, fee_by_input_count, is_token_transfer);
|
||||
if (!max_usable_money.first)
|
||||
continue;
|
||||
else if (max_usable_money.second < required_money_by_input_count.at(max_usable_money.first))
|
||||
@@ -437,7 +454,7 @@ select_inputs_func_t make_single_transfer_input_selector(
|
||||
|
||||
// Skip if not enough money in this selectable set for exact number of inputs...
|
||||
const auto max_usable_money = input_count_for_max_usable_money(input_candidates,
|
||||
input_candidate_subset, n_inputs, fee_by_input_count);
|
||||
input_candidate_subset, n_inputs, fee_by_input_count, is_token_transfer);
|
||||
if (max_usable_money.first != n_inputs)
|
||||
continue;
|
||||
else if (max_usable_money.second < required_money)
|
||||
|
||||
@@ -52,14 +52,17 @@ struct InputCandidate
|
||||
namespace InputSelectionFlags
|
||||
{
|
||||
// Quantum forward secrecy (ON = unsafe)
|
||||
static constexpr std::uint32_t ALLOW_EXTERNAL_INPUTS_IN_NORMAL_TRANSFERS = 1 << 0;
|
||||
static constexpr std::uint32_t ALLOW_PRE_CARROT_INPUTS_IN_NORMAL_TRANSFERS = 1 << 1;
|
||||
static constexpr std::uint32_t ALLOW_EXTERNAL_INPUTS_IN_NORMAL_TRANSFERS = 1 << 0; // 000..00000001
|
||||
static constexpr std::uint32_t ALLOW_PRE_CARROT_INPUTS_IN_NORMAL_TRANSFERS = 1 << 1; // 000..00000010
|
||||
static constexpr std::uint32_t ALLOW_MIXED_INTERNAL_EXTERNAL = 1 << 2;
|
||||
static constexpr std::uint32_t ALLOW_MIXED_CARROT_PRE_CARROT = 1 << 3;
|
||||
|
||||
// Amount handling
|
||||
static constexpr std::uint32_t IS_KNOWN_FEE_SUBTRACTABLE = 1 << 4;
|
||||
static constexpr std::uint32_t ALLOW_DUST = 1 << 5;
|
||||
|
||||
// Token transfer (fee is paid separately in SAL1 via rollup tx, so no fee for input selection)
|
||||
static constexpr std::uint32_t IS_TOKEN_TRANSFER = 1 << 6;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -77,10 +77,11 @@ struct subaddress_index_extended
|
||||
{
|
||||
subaddress_index index;
|
||||
AddressDeriveType derive_type;
|
||||
bool is_return_spend_key;
|
||||
};
|
||||
static inline bool operator==(const subaddress_index_extended &a, const subaddress_index_extended &b)
|
||||
{
|
||||
return a.index == b.index && a.derive_type == b.derive_type;
|
||||
return a.index == b.index && a.derive_type == b.derive_type && a.is_return_spend_key == b.is_return_spend_key;
|
||||
}
|
||||
static inline bool operator!=(const subaddress_index_extended &a, const subaddress_index_extended &b)
|
||||
{
|
||||
|
||||
@@ -60,6 +60,8 @@ void get_output_enote_proposals_from_proposal_v1(const CarrotTransactionProposal
|
||||
|
||||
// derive enote proposals
|
||||
size_t change_index;
|
||||
RCTOutputEnoteProposal return_enote_out;
|
||||
std::unordered_map<crypto::public_key, size_t> normal_payments_indices;
|
||||
get_output_enote_proposals(tx_proposal.normal_payment_proposals,
|
||||
selfsend_payment_proposal_cores,
|
||||
tx_proposal.dummy_encrypted_payment_id,
|
||||
@@ -67,8 +69,11 @@ void get_output_enote_proposals_from_proposal_v1(const CarrotTransactionProposal
|
||||
k_view_dev,
|
||||
tx_proposal.key_images_sorted.at(0),
|
||||
output_enote_proposals_out,
|
||||
return_enote_out,
|
||||
encrypted_payment_id_out,
|
||||
tx_proposal.tx_type,
|
||||
change_index,
|
||||
normal_payments_indices,
|
||||
payment_proposal_order_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -123,7 +128,13 @@ void make_pruned_transaction_from_proposal_v1(const CarrotTransactionProposalV1
|
||||
tx_proposal.key_images_sorted,
|
||||
tx_proposal.sources,
|
||||
tx_proposal.fee,
|
||||
encrypted_payment_id);
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
0, // tx_amount_burnt
|
||||
{}, // change_masks
|
||||
{}, // return_enote
|
||||
{0},
|
||||
encrypted_payment_id,
|
||||
/*hf_version=*/10);
|
||||
|
||||
// add extra payload and sort
|
||||
if (!tx_proposal.extra.empty())
|
||||
|
||||
@@ -67,8 +67,8 @@ struct CarrotPaymentProposalVerifiableSelfSendV1
|
||||
*
|
||||
* For exact details on what goes into the signable transaction hash, see `rct::get_pre_mlsag_hash`.
|
||||
*/
|
||||
struct CarrotTransactionProposalV1
|
||||
{
|
||||
struct CarrotTransactionProposalV1
|
||||
{
|
||||
/// Key images sorted in std::greater order
|
||||
std::vector<crypto::key_image> key_images_sorted;
|
||||
// sources in the same order as key_images_sorted.
|
||||
@@ -84,9 +84,23 @@ struct CarrotTransactionProposalV1
|
||||
encrypted_payment_id_t dummy_encrypted_payment_id;
|
||||
/// Fee to miner
|
||||
rct::xmr_amount fee;
|
||||
/// transaction type, e.g.
|
||||
cryptonote::transaction_type tx_type;
|
||||
/// how much money tx burns
|
||||
rct::xmr_amount amount_burnt;
|
||||
|
||||
/// used if this is a CREATE_TOKEN transaction
|
||||
cryptonote::token_metadata_t token;
|
||||
|
||||
/// This field is truly "extra". It should contain only tx.extra fields that aren't present in a
|
||||
/// normal Carrot transaction, i.e. NOT ephemeral pubkeys nor encrypted PIDs
|
||||
std::vector<std::uint8_t> extra;
|
||||
};
|
||||
|
||||
/// Used if this is a TOKEN_TRANSFER or ROLLUP transaction
|
||||
carrot::rollup_binding_tag_t rollup_binding_tag;
|
||||
|
||||
/// Used if this is a ROLLUP transaction
|
||||
cryptonote::layer2_rollup_data_t layer2_rollup_data;
|
||||
};
|
||||
|
||||
} //namespace carrot
|
||||
|
||||
@@ -90,7 +90,7 @@ static void append_additional_payment_proposal_if_necessary(
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
std::uint64_t get_carrot_default_tx_extra_size(const std::size_t n_outputs)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(n_outputs <= FCMP_PLUS_PLUS_MAX_OUTPUTS,
|
||||
CHECK_AND_ASSERT_THROW_MES(n_outputs <= CARROT_MAX_TX_OUTPUTS,
|
||||
"get_carrot_default_tx_extra_size: n_outputs too high: " << n_outputs);
|
||||
CHECK_AND_ASSERT_THROW_MES(n_outputs >= CARROT_MIN_TX_OUTPUTS,
|
||||
"get_carrot_default_tx_extra_size: n_outputs too low: " << n_outputs);
|
||||
@@ -117,6 +117,7 @@ void make_carrot_transaction_proposal_v1(const std::vector<CarrotPaymentProposal
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
select_inputs_func_t &&select_inputs,
|
||||
carve_fees_and_balance_func_t &&carve_fees_and_balance,
|
||||
const crypto::public_key &change_address_spend_pubkey,
|
||||
@@ -196,7 +197,7 @@ void make_carrot_transaction_proposal_v1(const std::vector<CarrotPaymentProposal
|
||||
const std::size_t n_inputs = selected_inputs.size();
|
||||
CARROT_CHECK_AND_THROW(n_inputs >= CARROT_MIN_TX_INPUTS,
|
||||
too_few_inputs, "input selection returned too few inputs: " << n_inputs);
|
||||
CARROT_CHECK_AND_THROW(n_inputs <= CARROT_MAX_TX_OUTPUTS,
|
||||
CARROT_CHECK_AND_THROW(n_inputs <= CARROT_MAX_TX_INPUTS,
|
||||
too_few_inputs, "input selection returned too many inputs: " << n_inputs);
|
||||
CARROT_CHECK_AND_THROW(fee_per_input_count.count(n_inputs),
|
||||
carrot_logic_error, "BUG: fee_per_input_count populated with holes, missing: " << n_inputs);
|
||||
@@ -208,16 +209,45 @@ void make_carrot_transaction_proposal_v1(const std::vector<CarrotPaymentProposal
|
||||
input_amount_sum += selected_input.amount;
|
||||
|
||||
// callback to balance the outputs with the fee and input sum
|
||||
carve_fees_and_balance(input_amount_sum, tx_proposal_out.fee, normal_payment_proposals, selfsend_payment_proposals);
|
||||
std::string asset_type = "SAL1"; // default to SAL1
|
||||
if (!normal_payment_proposals.empty()) {
|
||||
asset_type = normal_payment_proposals.at(0).asset_type;
|
||||
} else if (!selfsend_payment_proposals.empty()) {
|
||||
asset_type = selfsend_payment_proposals.at(0).proposal.asset_type;
|
||||
}
|
||||
uint64_t fee = tx_proposal_out.fee;
|
||||
if (asset_type != "SAL1") {
|
||||
// check here
|
||||
if (tx_type != cryptonote::transaction_type::BURN || asset_type != "SAL") {
|
||||
CARROT_CHECK_AND_THROW(cryptonote::is_valid_custom_asset_type(asset_type),
|
||||
carrot_logic_error, "make_carrot_transaction_proposal_v1: invalid asset type in payment proposals: " << asset_type);
|
||||
}
|
||||
|
||||
fee = 0; //fee is always in SAL1
|
||||
}
|
||||
carve_fees_and_balance(input_amount_sum, fee, normal_payment_proposals, selfsend_payment_proposals);
|
||||
|
||||
// sanity check balance
|
||||
input_amount_sum -= tx_proposal_out.fee;
|
||||
input_amount_sum -= fee;
|
||||
for (const CarrotPaymentProposalV1 &normal_payment_proposal : normal_payment_proposals)
|
||||
input_amount_sum -= normal_payment_proposal.amount;
|
||||
for (const CarrotPaymentProposalVerifiableSelfSendV1 &selfsend_payment_proposal : selfsend_payment_proposals)
|
||||
input_amount_sum -= selfsend_payment_proposal.proposal.amount;
|
||||
CHECK_AND_ASSERT_THROW_MES(input_amount_sum == 0,
|
||||
"make_carrot_transaction_proposal_v1: post-carved transaction does not balance");
|
||||
|
||||
if (tx_type != cryptonote::transaction_type::STAKE &&
|
||||
tx_type != cryptonote::transaction_type::BURN &&
|
||||
tx_type != cryptonote::transaction_type::CREATE_TOKEN &&
|
||||
tx_type != cryptonote::transaction_type::ROLLUP)
|
||||
{
|
||||
CHECK_AND_ASSERT_THROW_MES(input_amount_sum == 0,
|
||||
"make_carrot_transaction_proposal_v1: post-carved transaction does not balance");
|
||||
} else {
|
||||
tx_proposal_out.amount_burnt = input_amount_sum.convert_to<uint64_t>();
|
||||
CHECK_AND_ASSERT_THROW_MES(tx_proposal_out.amount_burnt >= 0,
|
||||
"make_carrot_transaction_proposal_v1: post-carved transaction burnt amount is negative: "
|
||||
<< tx_proposal_out.amount_burnt);
|
||||
input_amount_sum -= tx_proposal_out.amount_burnt;
|
||||
}
|
||||
|
||||
// collect and sort key images
|
||||
tx_proposal_out.key_images_sorted.reserve(selected_inputs.size());
|
||||
@@ -226,6 +256,9 @@ void make_carrot_transaction_proposal_v1(const std::vector<CarrotPaymentProposal
|
||||
std::sort(tx_proposal_out.key_images_sorted.begin(),
|
||||
tx_proposal_out.key_images_sorted.end(),
|
||||
std::greater{}); // consensus rules dictate inputs sorted in *reverse* lexicographical order since v7
|
||||
|
||||
// set the transaction type & new asset type
|
||||
tx_proposal_out.tx_type = tx_type;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void make_carrot_transaction_proposal_v1_transfer(
|
||||
@@ -234,11 +267,13 @@ void make_carrot_transaction_proposal_v1_transfer(
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
select_inputs_func_t &&select_inputs,
|
||||
const crypto::public_key &change_address_spend_pubkey,
|
||||
const subaddress_index_extended &change_address_index,
|
||||
const std::set<std::size_t> &subtractable_normal_payment_proposals,
|
||||
const std::set<std::size_t> &subtractable_selfsend_payment_proposals,
|
||||
const std::string &asset_type,
|
||||
CarrotTransactionProposalV1 &tx_proposal_out)
|
||||
{
|
||||
std::vector<CarrotPaymentProposalVerifiableSelfSendV1> selfsend_payment_proposals = selfsend_payment_proposals_in;
|
||||
@@ -259,7 +294,8 @@ void make_carrot_transaction_proposal_v1_transfer(
|
||||
.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = change_address_spend_pubkey,
|
||||
.amount = 0,
|
||||
.enote_type = add_payment_type_selfsend ? CarrotEnoteType::PAYMENT : CarrotEnoteType::CHANGE
|
||||
.enote_type = add_payment_type_selfsend ? CarrotEnoteType::PAYMENT : CarrotEnoteType::CHANGE,
|
||||
.asset_type = asset_type
|
||||
},
|
||||
.subaddr_index = change_address_index
|
||||
});
|
||||
@@ -268,7 +304,8 @@ void make_carrot_transaction_proposal_v1_transfer(
|
||||
carve_fees_and_balance_func_t carve_fees_and_balance =
|
||||
[
|
||||
&subtractable_normal_payment_proposals,
|
||||
&subtractable_selfsend_payment_proposals
|
||||
&subtractable_selfsend_payment_proposals,
|
||||
&tx_type
|
||||
]
|
||||
(
|
||||
const boost::multiprecision::uint128_t &input_sum_amount,
|
||||
@@ -377,6 +414,19 @@ void make_carrot_transaction_proposal_v1_transfer(
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(fee_remainder == 0,
|
||||
"make unsigned transaction transfer subtractable: bug: fee remainder at end of carve function");
|
||||
|
||||
// remove the self send payment we have made to ourself now that we have our change payment.
|
||||
if (tx_type == cryptonote::transaction_type::STAKE ||
|
||||
tx_type == cryptonote::transaction_type::BURN ||
|
||||
tx_type == cryptonote::transaction_type::CREATE_TOKEN ||
|
||||
tx_type == cryptonote::transaction_type::ROLLUP)
|
||||
{
|
||||
selfsend_payment_proposals.back().proposal.enote_ephemeral_pubkey =
|
||||
selfsend_payment_proposals.front().proposal.enote_ephemeral_pubkey;
|
||||
|
||||
selfsend_payment_proposals.erase(selfsend_payment_proposals.begin());
|
||||
}
|
||||
|
||||
}; //end carve_fees_and_balance
|
||||
|
||||
// make unsigned transaction with fee carving callback
|
||||
@@ -385,6 +435,7 @@ void make_carrot_transaction_proposal_v1_transfer(
|
||||
fee_per_weight,
|
||||
fee_quantization_mask,
|
||||
extra,
|
||||
tx_type,
|
||||
std::forward<select_inputs_func_t>(select_inputs),
|
||||
std::move(carve_fees_and_balance),
|
||||
change_address_spend_pubkey,
|
||||
@@ -398,9 +449,11 @@ void make_carrot_transaction_proposal_v1_sweep(
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
std::vector<CarrotSelectedInput> &&selected_inputs,
|
||||
const crypto::public_key &change_address_spend_pubkey,
|
||||
const subaddress_index_extended &change_address_index,
|
||||
const std::string &asset_type,
|
||||
CarrotTransactionProposalV1 &tx_proposal_out)
|
||||
{
|
||||
// sanity check payment proposals are provided
|
||||
@@ -423,6 +476,19 @@ void make_carrot_transaction_proposal_v1_sweep(
|
||||
CHECK_AND_ASSERT_THROW_MES(bool(normal_payment_proposals.size()) ^ bool(selfsend_payment_proposals.size()),
|
||||
"make carrot transaction proposal v1 sweep: both normal and self-send payment proposals are provided");
|
||||
|
||||
std::vector<CarrotPaymentProposalVerifiableSelfSendV1> selfsend_payment_proposals_inout{selfsend_payment_proposals};
|
||||
//if (tx_type == cryptonote::transaction_type::RETURN) {
|
||||
selfsend_payment_proposals_inout.push_back(carrot::CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
.proposal = carrot::CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = change_address_spend_pubkey,
|
||||
.amount = 0,
|
||||
.enote_type = carrot::CarrotEnoteType::CHANGE,
|
||||
.asset_type = asset_type
|
||||
},
|
||||
.subaddr_index = change_address_index
|
||||
});
|
||||
// }
|
||||
|
||||
const bool is_selfsend_sweep = !selfsend_payment_proposals.empty();
|
||||
|
||||
// define input selection callback, which is just a shuttle for `selected_inputs`
|
||||
@@ -473,10 +539,11 @@ void make_carrot_transaction_proposal_v1_sweep(
|
||||
|
||||
// make unsigned transaction with sweep carving callback and selected inputs
|
||||
make_carrot_transaction_proposal_v1(normal_payment_proposals,
|
||||
selfsend_payment_proposals,
|
||||
selfsend_payment_proposals_inout,
|
||||
fee_per_weight,
|
||||
fee_quantization_mask,
|
||||
extra,
|
||||
tx_type,
|
||||
std::move(select_inputs),
|
||||
std::move(carve_fees_and_balance),
|
||||
change_address_spend_pubkey,
|
||||
|
||||
@@ -92,19 +92,26 @@ static size_t estimate_rct_tx_size_carrot(int n_inputs, int mixin, int n_outputs
|
||||
size += 1 + 6;
|
||||
|
||||
// vin
|
||||
size += n_inputs * (1+6+4+(mixin+1)*2+32);
|
||||
size += n_inputs * (1+1+4+(mixin+1)*2+32);
|
||||
|
||||
// vout
|
||||
size += n_outputs * (3+4+16+32);
|
||||
size += n_outputs * (1+1+32+4+3+16);
|
||||
|
||||
// extra
|
||||
size += extra_size;
|
||||
|
||||
// rct signatures
|
||||
|
||||
// type
|
||||
size += 1;
|
||||
|
||||
// amount_burnt
|
||||
size += 8;
|
||||
|
||||
// return_address data
|
||||
// NOTE: this will be wrong by 21 bytes for STAKE TXs using `protocol_tx_data_t`
|
||||
size += n_outputs * (32 + 1);
|
||||
|
||||
// rct signatures
|
||||
|
||||
// rangeSigs
|
||||
if (bulletproof || bulletproof_plus)
|
||||
{
|
||||
@@ -187,6 +194,7 @@ void make_carrot_transaction_proposal_v1(const std::vector<CarrotPaymentProposal
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
select_inputs_func_t &&select_inputs,
|
||||
carve_fees_and_balance_func_t &&carve_fees_and_balance,
|
||||
const crypto::public_key &change_address_spend_pubkey,
|
||||
@@ -199,11 +207,13 @@ void make_carrot_transaction_proposal_v1_transfer(
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
select_inputs_func_t &&select_inputs,
|
||||
const crypto::public_key &change_address_spend_pubkey,
|
||||
const subaddress_index_extended &change_address_index,
|
||||
const std::set<std::size_t> &subtractable_normal_payment_proposals,
|
||||
const std::set<std::size_t> &subtractable_selfsend_payment_proposals,
|
||||
const std::string &asset_type,
|
||||
CarrotTransactionProposalV1 &tx_proposal_out);
|
||||
|
||||
void make_carrot_transaction_proposal_v1_sweep(
|
||||
@@ -212,9 +222,11 @@ void make_carrot_transaction_proposal_v1_sweep(
|
||||
const rct::xmr_amount fee_per_weight,
|
||||
const rct::xmr_amount fee_quantization_mask,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
std::vector<CarrotSelectedInput> &&selected_inputs,
|
||||
const crypto::public_key &change_address_spend_pubkey,
|
||||
const subaddress_index_extended &change_address_index,
|
||||
const std::string &asset_type,
|
||||
CarrotTransactionProposalV1 &tx_proposal_out);
|
||||
|
||||
} //namespace carrot
|
||||
|
||||
@@ -183,28 +183,33 @@ namespace cryptonote
|
||||
bool checkpoints::init_default_checkpoints(network_type nettype)
|
||||
{
|
||||
if (nettype == MAINNET) {
|
||||
ADD_CHECKPOINT2(1, "b6b45052e7e182ebaeb14ab713db29ad979115e664d766aa0910e325564a27a6", "0x2");
|
||||
ADD_CHECKPOINT2(10, "82724681cf6bd934eb3253d041de50206a77627ce40ffe418ce6e0fe392ec684", "0x7812a");
|
||||
ADD_CHECKPOINT2(20, "4dac7b512d876df05bfa4f39b8dbacd75cb1483fbced8bfc5446ebe21b25a04f", "0xba98f");
|
||||
ADD_CHECKPOINT2(30, "668246360c93ef791a59157cec9cd09722b32a966051feea399082433138f07b", "0xcc235");
|
||||
ADD_CHECKPOINT2(40, "9a4183bc1d6e9828eac46505c5ef37ae5447ba6c9325dca02be9e1201f939a7d", "0xdf077");
|
||||
ADD_CHECKPOINT2(50, "5cd8b089d2e77aed9b803b398c6bff07ca652100cb8fa114c91b72509aeeb7e9", "0xf37eb");
|
||||
ADD_CHECKPOINT2(60, "0e1acf00dd38e0757996dcdc4b69ad54baf7ebe10ae1e8168b192acb1a0ed7f2", "0x10993b");
|
||||
ADD_CHECKPOINT2(70, "988977507f388221a927e279307b548a0ae0de10ded8c4f22c315e1b483f921a", "0x121537");
|
||||
ADD_CHECKPOINT2(80, "88ea1c49b20e7596e21ca8137b2a9fa98558df269a15816fe7d7495f1c63ea43", "0x13a290");
|
||||
ADD_CHECKPOINT2(90, "254800bb6f9794aad95b2226ffc1a1eef0a817472e1877ae08fac6becb55b147", "0x153a55");
|
||||
ADD_CHECKPOINT2(100, "ba8d75fad878af26ac2504b4868893a7f86c59f013d0f096925cf53271dd04e8", "0x16e91e");
|
||||
ADD_CHECKPOINT2(110, "dca0779bfe403730b923fa0918645daeec6096b953be2c554f133460c6fcce35", "0x18acb9");
|
||||
ADD_CHECKPOINT2(120, "5a57287f6b5c105ae264b88050731c5b9ad1313b916143d7585af1d345e70247", "0x1a88f5");
|
||||
ADD_CHECKPOINT2(130, "4fd292ac0774461e968924f8097e78ec03eee43a2997deaddbc7993e470a61d6", "0x1c6edd");
|
||||
ADD_CHECKPOINT2(140, "5a3b6ceeef5fd498ea3330acb8a0e87f2c1566c9b0100ad67237e5664d1f053b", "0x1e4991");
|
||||
ADD_CHECKPOINT2(150, "78f26d08d39f7d5e1a3548277321471e16c95096fa9bcecbe8a420d406ee249b", "0x202406");
|
||||
ADD_CHECKPOINT2(160, "7acaab1037ccfbadd3126d2612d5dc154020297f980df0b8df462f9c761d3326", "0x22154b");
|
||||
ADD_CHECKPOINT2(170, "9541ae934e40fa6749ca3453e47cf5fdf38efbac9efcaa2714121e8a21dd2d24", "0x241ce7");
|
||||
ADD_CHECKPOINT2(180, "e20bc8ac6aabb6b0792f23a29ce42a577c6a57d177a8ac1a51b68fb6de508045", "0x262b40");
|
||||
ADD_CHECKPOINT2(190, "f69fdad7a15471b63a82668b618ee5b2a384291269d944b11974a723c1604124", "0x2856a3");
|
||||
ADD_CHECKPOINT2(200, "eba53fa7006dfcdc837a56c0bc8f0e1883cf34861c26934d680252a6878a3f5d", "0x2aa022");
|
||||
ADD_CHECKPOINT2(90000, "e125b5c1b26521f98e29df6ec88f041c176a2c0a3fcacd5bd0ad2278e9b02fd2", "0xc99801f937888"); // 3546475285149832
|
||||
ADD_CHECKPOINT2(1, "b6b45052e7e182ebaeb14ab713db29ad979115e664d766aa0910e325564a27a6", "0x2");
|
||||
ADD_CHECKPOINT2(10, "82724681cf6bd934eb3253d041de50206a77627ce40ffe418ce6e0fe392ec684", "0x7812a");
|
||||
ADD_CHECKPOINT2(20, "4dac7b512d876df05bfa4f39b8dbacd75cb1483fbced8bfc5446ebe21b25a04f", "0xba98f");
|
||||
ADD_CHECKPOINT2(30, "668246360c93ef791a59157cec9cd09722b32a966051feea399082433138f07b", "0xcc235");
|
||||
ADD_CHECKPOINT2(40, "9a4183bc1d6e9828eac46505c5ef37ae5447ba6c9325dca02be9e1201f939a7d", "0xdf077");
|
||||
ADD_CHECKPOINT2(50, "5cd8b089d2e77aed9b803b398c6bff07ca652100cb8fa114c91b72509aeeb7e9", "0xf37eb");
|
||||
ADD_CHECKPOINT2(60, "0e1acf00dd38e0757996dcdc4b69ad54baf7ebe10ae1e8168b192acb1a0ed7f2", "0x10993b");
|
||||
ADD_CHECKPOINT2(70, "988977507f388221a927e279307b548a0ae0de10ded8c4f22c315e1b483f921a", "0x121537");
|
||||
ADD_CHECKPOINT2(80, "88ea1c49b20e7596e21ca8137b2a9fa98558df269a15816fe7d7495f1c63ea43", "0x13a290");
|
||||
ADD_CHECKPOINT2(90, "254800bb6f9794aad95b2226ffc1a1eef0a817472e1877ae08fac6becb55b147", "0x153a55");
|
||||
ADD_CHECKPOINT2(100, "ba8d75fad878af26ac2504b4868893a7f86c59f013d0f096925cf53271dd04e8", "0x16e91e");
|
||||
ADD_CHECKPOINT2(110, "dca0779bfe403730b923fa0918645daeec6096b953be2c554f133460c6fcce35", "0x18acb9");
|
||||
ADD_CHECKPOINT2(120, "5a57287f6b5c105ae264b88050731c5b9ad1313b916143d7585af1d345e70247", "0x1a88f5");
|
||||
ADD_CHECKPOINT2(130, "4fd292ac0774461e968924f8097e78ec03eee43a2997deaddbc7993e470a61d6", "0x1c6edd");
|
||||
ADD_CHECKPOINT2(140, "5a3b6ceeef5fd498ea3330acb8a0e87f2c1566c9b0100ad67237e5664d1f053b", "0x1e4991");
|
||||
ADD_CHECKPOINT2(150, "78f26d08d39f7d5e1a3548277321471e16c95096fa9bcecbe8a420d406ee249b", "0x202406");
|
||||
ADD_CHECKPOINT2(160, "7acaab1037ccfbadd3126d2612d5dc154020297f980df0b8df462f9c761d3326", "0x22154b");
|
||||
ADD_CHECKPOINT2(170, "9541ae934e40fa6749ca3453e47cf5fdf38efbac9efcaa2714121e8a21dd2d24", "0x241ce7");
|
||||
ADD_CHECKPOINT2(180, "e20bc8ac6aabb6b0792f23a29ce42a577c6a57d177a8ac1a51b68fb6de508045", "0x262b40");
|
||||
ADD_CHECKPOINT2(190, "f69fdad7a15471b63a82668b618ee5b2a384291269d944b11974a723c1604124", "0x2856a3");
|
||||
ADD_CHECKPOINT2(200, "eba53fa7006dfcdc837a56c0bc8f0e1883cf34861c26934d680252a6878a3f5d", "0x2aa022");
|
||||
ADD_CHECKPOINT2(90000, "e125b5c1b26521f98e29df6ec88f041c176a2c0a3fcacd5bd0ad2278e9b02fd2", "0xc99801f937888"); // 3546475285149832
|
||||
ADD_CHECKPOINT2(100000, "ff4e8ec805d5bfbcd01f350ac071be1d944ba73e0d27e37d12acb549902b3f3d", "0xDA97F5697F7D8"); // 3845539075979224
|
||||
ADD_CHECKPOINT2(150000, "c43281eb5b2a41ee77a4465735e4820c6d14d473b568df7987541afc48f18568", "0x12BDA9ED687AAF"); // 5275087110961839
|
||||
ADD_CHECKPOINT2(225000, "7648405f7cfb24341d9580275b518bb3713c68e970f547faa0b3bcae450d9ec2", "0x18CD5F1B7BA43A"); // 6981207807730746
|
||||
ADD_CHECKPOINT2(300000, "a18ca65464c1f2d876dd3a00643c9be265655d6bca364eccc5e3d628b9a5cd2c", "0x1F0C2A50FE631C"); // 8739100165038876
|
||||
ADD_CHECKPOINT2(375000, "07f0c907cc5cb44cef88e5899a411adddd4b0a4419210906e0583efdcafb499f", "0x240C7F9742F265"); // 10146841299710565
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -138,13 +138,6 @@ bool keys_match_internal_values(const std::unordered_map<KeyT, ValueT> &map, Pre
|
||||
|
||||
return true;
|
||||
}
|
||||
/// convenience wrapper for getting the last element after emplacing back
|
||||
template <typename ContainerT>
|
||||
typename ContainerT::value_type& add_element(ContainerT &container)
|
||||
{
|
||||
container.emplace_back();
|
||||
return container.back();
|
||||
}
|
||||
/// convenience erasor for unordered maps: std::erase_if(std::unordered_map) is C++20
|
||||
template <typename KeyT, typename ValueT, typename PredT>
|
||||
void for_all_in_map_erase_if(std::unordered_map<KeyT, ValueT> &map_inout, PredT predicate)
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#define DEBUG_BREAK() asm volatile("int $3")
|
||||
#elif defined(__aarch64__)
|
||||
#define DEBUG_BREAK() asm volatile("brk #0xf000")
|
||||
#elif defined(__arm__)
|
||||
#define DEBUG_BREAK() asm volatile(".inst 0xe7f001f0") // Encoding for bkpt #0xf01, common for ARM32
|
||||
#else
|
||||
#error "Unsupported architecture for DEBUG_BREAK"
|
||||
#endif
|
||||
@@ -71,6 +71,7 @@ monero_add_library(cncrypto
|
||||
target_link_libraries(cncrypto
|
||||
PUBLIC
|
||||
epee
|
||||
mx25519_static
|
||||
randomx
|
||||
${Boost_SYSTEM_LIBRARY}
|
||||
${SODIUM_LIBRARY}
|
||||
|
||||
@@ -887,4 +887,7 @@ const ge_p3 ge_p3_H = {
|
||||
{5858699, 5096796, 21321203, -7536921, -5553480, -11439507, -5627669, 15045946, 19977121, 5275251},
|
||||
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{23443568, -5110398, -8776029, -4345135, 6889568, -14710814, 7474843, 3279062, 14550766, -7453428}
|
||||
};
|
||||
};
|
||||
|
||||
// Precomputed sqrt(-486664) mod p as 32-byte little-endian array
|
||||
const fe fe_sqrt_m486664 = {12222970, 8312128, 11511410, -9067497, 15300785, 241793, -25456130, -14121551, 12187136, -3972024};
|
||||
|
||||
+125
-2
@@ -104,6 +104,21 @@ void fe_1(fe h) {
|
||||
h[9] = 0;
|
||||
}
|
||||
|
||||
int fe_equal(const fe a, const fe b)
|
||||
{
|
||||
fe t;
|
||||
fe_sub(t, a, b);
|
||||
return fe_isnonzero(t) == 0;
|
||||
}
|
||||
|
||||
void ge_from_xy(ge_p3 *out, const fe x, const fe y)
|
||||
{
|
||||
fe_1(out->Z); // Z = 1
|
||||
fe_copy(out->X, x); // X = x
|
||||
fe_copy(out->Y, y); // Y = y
|
||||
fe_mul(out->T, x, y); // T = x*y
|
||||
}
|
||||
|
||||
/* From fe_add.c */
|
||||
|
||||
/*
|
||||
@@ -365,7 +380,7 @@ int fe_isnegative(const fe f) {
|
||||
|
||||
/* From fe_isnonzero.c, modified */
|
||||
|
||||
static int fe_isnonzero(const fe f) {
|
||||
int fe_isnonzero(const fe f) {
|
||||
unsigned char s[32];
|
||||
fe_tobytes(s, f);
|
||||
return (((int) (s[0] | s[1] | s[2] | s[3] | s[4] | s[5] | s[6] | s[7] | s[8] |
|
||||
@@ -3967,6 +3982,114 @@ int edwards_bytes_to_x25519_vartime(unsigned char *xbytes, const unsigned char *
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Precomputed sqrt(-1) from Monero (fe_sqrtm1 in crypto-ops-data.c)
|
||||
extern const fe fe_sqrtm1;
|
||||
extern const fe fe_sqrt_m486664;
|
||||
|
||||
// Function to recover v from u (returns 0 on success, -1 if not on curve)
|
||||
int fe_sqrt_mont(fe v_out, const fe u_in) {
|
||||
fe rhs;
|
||||
fe t0, t1, t2;
|
||||
fe candidate, c2, check;
|
||||
|
||||
// Compute rhs = u^3 + A u^2 + u, A=486662
|
||||
fe A_fe;
|
||||
fe_frombytes_vartime(A_fe, (const unsigned char[]){0x06, 0x6D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); // Correct little-endian 486662
|
||||
|
||||
fe_sq(t0, u_in); // t0 = u^2
|
||||
fe_mul(t1, t0, u_in); // t1 = u^3
|
||||
fe_mul(t2, t0, A_fe); // t2 = A u^2
|
||||
fe_add(rhs, t1, t2); // u^3 + A u^2
|
||||
fe_add(rhs, rhs, u_in); // + u
|
||||
|
||||
// The exponentiation chain for (p+3)/8
|
||||
fe_1(t1);
|
||||
fe_sq(t0, t1);
|
||||
fe_mul(t0, t0, t1);
|
||||
fe_sq(candidate, t0);
|
||||
fe_mul(candidate, candidate, t1);
|
||||
fe_mul(candidate, candidate, rhs);
|
||||
fe_pow22523(candidate, candidate);
|
||||
fe_mul(candidate, candidate, t0);
|
||||
fe_mul(candidate, candidate, rhs);
|
||||
|
||||
// Check c^2 == rhs or -rhs
|
||||
fe_sq(c2, candidate);
|
||||
fe_sub(check, c2, rhs);
|
||||
if (fe_isnonzero(check)) {
|
||||
fe_add(check, c2, rhs);
|
||||
if (fe_isnonzero(check)) {
|
||||
return -1; // Not a quadratic residue
|
||||
}
|
||||
fe_mul(candidate, candidate, fe_sqrtm1); // Adjust with sqrt(-1)
|
||||
}
|
||||
|
||||
// Output v (principal root; flip to -v if needed for your map)
|
||||
fe_copy(v_out, candidate);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mont_to_ed(fe x_out, fe y_out, const fe u, const fe v) {
|
||||
fe inv_v, temp;
|
||||
fe t1, t2, inv_t2;
|
||||
fe one;
|
||||
fe_1(one);
|
||||
|
||||
fe_invert(inv_v, v); // 1/v
|
||||
fe_mul(temp, u, inv_v); // u/v
|
||||
fe_mul(x_out, fe_sqrt_m486664, temp); // sqrt(-486664) * (u/v)
|
||||
|
||||
fe_sub(t1, u, one); // u - 1
|
||||
fe_add(t2, u, one); // u + 1
|
||||
fe_invert(inv_t2, t2);
|
||||
fe_mul(y_out, t1, inv_t2); // (u-1)/(u+1)
|
||||
}
|
||||
|
||||
void ed_to_mont(fe u_out, fe v_out, const fe x, const fe y) {
|
||||
fe t1, t2, inv_t2;
|
||||
fe one;
|
||||
fe_1(one);
|
||||
|
||||
fe_add(t1, one, y); // 1 + y
|
||||
fe_sub(t2, one, y); // 1 - y
|
||||
fe_invert(inv_t2, t2);
|
||||
fe_mul(u_out, t1, inv_t2); // (1+y)/(1-y)
|
||||
|
||||
fe inv_x;
|
||||
fe_invert(inv_x, x); // 1/x
|
||||
fe_mul(t1, u_out, inv_x); // u / x
|
||||
fe_mul(v_out, fe_sqrt_m486664, t1); // sqrt(-486664) * (u/x)
|
||||
}
|
||||
|
||||
// Usage: Add two Montgomery points
|
||||
void add_mont_points(fe u3, fe v3, const fe u1, const fe v1, const fe u2, const fe v2) {
|
||||
ge_p3 P_ed, Q_ed, sum_ed;
|
||||
|
||||
// Convert to Edwards
|
||||
fe x1, y1, x2, y2;
|
||||
mont_to_ed(x1, y1, u1, v1);
|
||||
mont_to_ed(x2, y2, u2, v2);
|
||||
|
||||
// Load into ge_p3 (assume Z=1, T=x*y for affine)
|
||||
fe_1(P_ed.Z); fe_mul(P_ed.T, x1, y1); fe_copy(P_ed.X, x1); fe_copy(P_ed.Y, y1);
|
||||
fe_1(Q_ed.Z); fe_mul(Q_ed.T, x2, y2); fe_copy(Q_ed.X, x2); fe_copy(Q_ed.Y, y2);
|
||||
|
||||
// Add using ge_
|
||||
ge_cached Q_cached;
|
||||
ge_p3_to_cached(&Q_cached, &Q_ed);
|
||||
ge_p1p1 sum_p1p1;
|
||||
ge_add(&sum_p1p1, &P_ed, &Q_cached);
|
||||
ge_p1p1_to_p3(&sum_ed, &sum_p1p1);
|
||||
|
||||
// Convert back (normalize to affine: divide by Z)
|
||||
fe inv_z;
|
||||
fe_invert(inv_z, sum_ed.Z);
|
||||
fe x_out, y_out;
|
||||
fe_mul(x_out, sum_ed.X, inv_z);
|
||||
fe_mul(y_out, sum_ed.Y, inv_z);
|
||||
ed_to_mont(u3, v3, x_out, y_out);
|
||||
}
|
||||
|
||||
int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p) {
|
||||
// https://eprint.iacr.org/2008/522
|
||||
// X == T == 0 and Y/Z == 1
|
||||
@@ -4063,4 +4186,4 @@ void fe_dbl(fe h, const fe f)
|
||||
// Reduce the output for safety to ensure the result can be used as input to
|
||||
// fe_add or fe_sub without an extra call to fe_reduce
|
||||
fe_reduce(h, h_res);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-1
@@ -176,6 +176,11 @@ int sc_isnonzero(const unsigned char *); /* Doesn't normalize */
|
||||
void ge_p3_to_x25519(unsigned char *xbytes, const ge_p3 *h);
|
||||
int edwards_bytes_to_x25519_vartime(unsigned char *xbytes, const unsigned char *s);
|
||||
|
||||
int fe_sqrt_mont(fe v_out, const fe u_in);
|
||||
void mont_to_ed(fe x_out, fe y_out, const fe u, const fe v);
|
||||
void ed_to_mont(fe u_out, fe v_out, const fe x, const fe y);
|
||||
void add_mont_points(fe u3, fe v3, const fe u1, const fe v1, const fe u2, const fe v2);
|
||||
|
||||
// internal
|
||||
uint64_t load_3(const unsigned char *in);
|
||||
uint64_t load_4(const unsigned char *in);
|
||||
@@ -192,10 +197,14 @@ void fe_sq(fe h, const fe f);
|
||||
void fe_sub(fe h, const fe f, const fe g);
|
||||
void fe_0(fe h);
|
||||
void fe_1(fe h);
|
||||
int fe_equal(const fe a, const fe b);
|
||||
void ge_from_xy(ge_p3 *out, const fe x, const fe y);
|
||||
|
||||
int fe_isnonzero(const fe f);
|
||||
|
||||
int ge_p3_is_point_at_infinity_vartime(const ge_p3 *p);
|
||||
|
||||
void fe_ed_y_derivatives_to_wei_x(unsigned char *wei_x, const fe inv_one_minus_y, const fe one_plus_y);
|
||||
|
||||
void fe_reduce(fe reduced_f, const fe f);
|
||||
void fe_dbl(fe h, const fe f);
|
||||
void fe_dbl(fe h, const fe f);
|
||||
|
||||
+558
-1
@@ -41,6 +41,7 @@
|
||||
#include "common/varint.h"
|
||||
#include "warnings.h"
|
||||
#include "crypto.h"
|
||||
#include "mx25519.h"
|
||||
#include "hash.h"
|
||||
|
||||
#include "cryptonote_config.h"
|
||||
@@ -90,6 +91,16 @@ namespace crypto {
|
||||
return &reinterpret_cast<const unsigned char &>(scalar);
|
||||
}
|
||||
|
||||
static const mx25519_impl* get_mx25519_impl()
|
||||
{
|
||||
static std::once_flag of;
|
||||
static const mx25519_impl *impl;
|
||||
std::call_once(of, [&](){ impl = mx25519_select_impl(MX25519_TYPE_AUTO); });
|
||||
if (impl == nullptr)
|
||||
throw std::runtime_error("failed to obtain a mx25519 implementation");
|
||||
return impl;
|
||||
}
|
||||
|
||||
boost::mutex &get_random_lock()
|
||||
{
|
||||
static boost::mutex random_lock;
|
||||
@@ -504,6 +515,391 @@ namespace crypto {
|
||||
memwipe(&k, sizeof(k));
|
||||
}
|
||||
|
||||
void crypto_ops::generate_carrot_tx_proof(
|
||||
const hash &prefix_hash,
|
||||
const public_key &R, // X25519 u-coordinate
|
||||
const public_key &A, // Ed25519
|
||||
const boost::optional<public_key> &B, // Ed if present
|
||||
const public_key &D, // X25519 u-coordinate
|
||||
const secret_key &r,
|
||||
const secret_key &a,
|
||||
signature &sig)
|
||||
{
|
||||
// Check if we are sender or receiver
|
||||
if (r != crypto::null_skey) {
|
||||
// SENDER
|
||||
generate_carrot_tx_proof_as_sender(prefix_hash, R, A, B, D, r, a, sig);
|
||||
return;
|
||||
}
|
||||
|
||||
// RECEIVER
|
||||
|
||||
// Load points (A and B and R) into ge_p3
|
||||
ge_p3 A_p3;
|
||||
ge_p3 B_p3;
|
||||
ge_p3 R_p3;
|
||||
|
||||
if (ge_frombytes_vartime(&A_p3, &A) != 0)
|
||||
throw std::runtime_error("recipient view pubkey is invalid");
|
||||
|
||||
if (B && ge_frombytes_vartime(&B_p3, &*B) != 0)
|
||||
throw std::runtime_error("recipient spend pubkey is invalid");
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
{
|
||||
// Debug check D == a*R
|
||||
mx25519_pubkey D_x25519;
|
||||
mx25519_scmul_key(get_mx25519_impl(),
|
||||
&D_x25519,
|
||||
reinterpret_cast<const mx25519_privkey*>(&a),
|
||||
reinterpret_cast<const mx25519_pubkey*>(&R));
|
||||
public_key dbg_D;
|
||||
memcpy(&dbg_D, &D_x25519, sizeof(mx25519_pubkey));
|
||||
assert(D == dbg_D);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// 1. Pick random nonce k
|
||||
//
|
||||
crypto::secret_key k;
|
||||
random_scalar(k);
|
||||
|
||||
static const public_key zero = {{
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
}};
|
||||
|
||||
s_comm_2 buf;
|
||||
buf.msg = prefix_hash;
|
||||
buf.D = D; // X25519 u-coord
|
||||
buf.R = R; // X25519 u-coord
|
||||
buf.A = A; // Ed25519
|
||||
buf.B = B ? *B : zero;
|
||||
|
||||
cn_fast_hash(config::HASH_KEY_TXPROOF_V2,
|
||||
sizeof(config::HASH_KEY_TXPROOF_V2)-1,
|
||||
buf.sep);
|
||||
|
||||
//
|
||||
// 2. Compute X = ConvertPointE(k*G or k*B)
|
||||
//
|
||||
ge_p3 kB_or_kG_p3;
|
||||
if (B)
|
||||
ge_scalarmult_p3(&kB_or_kG_p3, &k, &B_p3);
|
||||
else
|
||||
ge_scalarmult_base(&kB_or_kG_p3, &k);
|
||||
mx25519_pubkey X_x25519;
|
||||
ge_p3_to_x25519(X_x25519.data, &kB_or_kG_p3);
|
||||
memcpy(&buf.X, &X_x25519, sizeof(mx25519_pubkey));
|
||||
|
||||
//
|
||||
// 3. Compute Y = k*R
|
||||
//
|
||||
mx25519_pubkey Y;
|
||||
mx25519_scmul_key(get_mx25519_impl(),
|
||||
&Y,
|
||||
reinterpret_cast<const mx25519_privkey*>(&k),
|
||||
reinterpret_cast<const mx25519_pubkey*>(&R));
|
||||
memcpy(&buf.Y, &Y, sizeof(mx25519_pubkey));
|
||||
|
||||
// ---------- Extract and lift R ----------
|
||||
fe u_R;
|
||||
fe_frombytes_vartime(u_R, (const unsigned char *)&R);
|
||||
|
||||
fe v_R_cand;
|
||||
if (fe_sqrt_mont(v_R_cand, u_R) != 0)
|
||||
throw std::runtime_error("R not on curve");
|
||||
|
||||
fe x1, y1, x2, y2, v_R_neg;
|
||||
ge_p3 R_ed1, R_ed2;
|
||||
|
||||
// +v (principal)
|
||||
mont_to_ed(x1, y1, u_R, v_R_cand);
|
||||
ge_from_xy(&R_ed1, x1, y1);
|
||||
|
||||
// -v
|
||||
fe_neg(v_R_neg, v_R_cand);
|
||||
mont_to_ed(x2, y2, u_R, v_R_neg);
|
||||
ge_from_xy(&R_ed2, x2, y2);
|
||||
|
||||
// Arbitrarily choose R_sign = true (principal v from fe_sqrt_mont)
|
||||
bool R_sign = true;
|
||||
ge_p3 R_ed_correct = R_ed1; // +v
|
||||
|
||||
// ---------- Extract and lift D (consistent with chosen R_sign) ----------
|
||||
fe u_D;
|
||||
fe_frombytes_vartime(u_D, (const unsigned char *)&D);
|
||||
|
||||
fe v_D_cand;
|
||||
if (fe_sqrt_mont(v_D_cand, u_D) != 0)
|
||||
throw std::runtime_error("D not on curve");
|
||||
|
||||
fe x3, y3, x4, y4, v_D_neg;
|
||||
|
||||
// Compute D_ed_true = a * R_ed_correct
|
||||
ge_p3 D_ed_true;
|
||||
ge_scalarmult_p3(&D_ed_true, &a, &R_ed_correct);
|
||||
|
||||
// Normalize to affine for matching
|
||||
fe inv_z;
|
||||
fe_invert(inv_z, D_ed_true.Z);
|
||||
fe xd_true, yd_true;
|
||||
fe_mul(xd_true, D_ed_true.X, inv_z);
|
||||
fe_mul(yd_true, D_ed_true.Y, inv_z);
|
||||
|
||||
// +v for D
|
||||
mont_to_ed(x3, y3, u_D, v_D_cand);
|
||||
bool D_match1 = fe_equal(x3, xd_true) && fe_equal(y3, yd_true); // Affine match (mont_to_ed gives affine x,y)
|
||||
|
||||
// -v for D
|
||||
fe_neg(v_D_neg, v_D_cand);
|
||||
mont_to_ed(x4, y4, u_D, v_D_neg);
|
||||
bool D_match2 = fe_equal(x4, xd_true) && fe_equal(y4, yd_true);
|
||||
|
||||
bool D_sign = false;
|
||||
if (D_match1)
|
||||
D_sign = true;
|
||||
else if (D_match2)
|
||||
D_sign = false;
|
||||
else
|
||||
throw std::runtime_error("D lift mismatch with computed D_ed_true");
|
||||
|
||||
// Pack signs (MSB is set to [1] for outbound, [0] for inbound
|
||||
sig.sign_mask =
|
||||
(R_sign ? 0x01 : 0x00) |
|
||||
(D_sign ? 0x02 : 0x00);
|
||||
|
||||
struct {
|
||||
s_comm_2 buf;
|
||||
uint8_t sign_mask;
|
||||
} challenge_hash;
|
||||
|
||||
challenge_hash.buf = buf;
|
||||
challenge_hash.sign_mask = sig.sign_mask;
|
||||
|
||||
//
|
||||
// 7. Compute challenge c = H(prefix_hash || … || sign_mask)
|
||||
//
|
||||
hash_to_scalar(&challenge_hash, sizeof(challenge_hash), sig.c);
|
||||
|
||||
//
|
||||
// 8. Compute response z = k - c*a
|
||||
//
|
||||
sc_mulsub(&sig.r, &sig.c, &unwrap(a), &k);
|
||||
|
||||
memwipe(&k, sizeof(k));
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
bool ok = check_carrot_tx_proof(prefix_hash, R, A, B, D, sig);
|
||||
assert(ok);
|
||||
#endif
|
||||
}
|
||||
|
||||
void crypto_ops::generate_carrot_tx_proof_as_sender(
|
||||
const hash &prefix_hash,
|
||||
const public_key &R, // X25519 u-coordinate
|
||||
const public_key &A, // Ed25519
|
||||
const boost::optional<public_key> &B, // Ed if present
|
||||
const public_key &D, // X25519 u-coordinate
|
||||
const secret_key &r,
|
||||
const secret_key &a,
|
||||
signature &sig)
|
||||
{
|
||||
// Load only Ed points (A and B) into ge_p3
|
||||
ge_p3 A_p3;
|
||||
ge_p3 B_p3;
|
||||
|
||||
if (ge_frombytes_vartime(&A_p3, &A) != 0)
|
||||
throw std::runtime_error("recipient view pubkey is invalid");
|
||||
|
||||
if (B && ge_frombytes_vartime(&B_p3, &*B) != 0)
|
||||
throw std::runtime_error("recipient spend pubkey is invalid");
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
{
|
||||
assert(sc_check(&r) == 0);
|
||||
|
||||
// Debug check R == ConvertPointE(r*G or r*B)
|
||||
public_key dbg_R;
|
||||
ge_p3 dbg_R_p3;
|
||||
|
||||
if (B)
|
||||
ge_scalarmult_p3(&dbg_R_p3, &r, &B_p3);
|
||||
else
|
||||
ge_scalarmult_base(&dbg_R_p3, &r);
|
||||
|
||||
mx25519_pubkey R_x25519;
|
||||
ge_p3_to_x25519(R_x25519.data, &dbg_R_p3);
|
||||
|
||||
memcpy(&dbg_R, &R_x25519, sizeof(mx25519_pubkey));
|
||||
assert(R == dbg_R);
|
||||
|
||||
// Debug check D == ConvertPointE(r*A)
|
||||
public_key dbg_D;
|
||||
ge_p3 dbg_D_p3;
|
||||
ge_scalarmult_p3(&dbg_D_p3, &r, &A_p3);
|
||||
|
||||
mx25519_pubkey D_x25519;
|
||||
ge_p3_to_x25519(D_x25519.data, &dbg_D_p3);
|
||||
|
||||
memcpy(&dbg_D, &D_x25519, sizeof(mx25519_pubkey));
|
||||
assert(D == dbg_D);
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// 1. Pick random nonce k
|
||||
//
|
||||
ec_scalar k;
|
||||
random_scalar(k);
|
||||
|
||||
static const ec_point zero = {{
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
}};
|
||||
|
||||
s_comm_2 buf;
|
||||
buf.msg = prefix_hash;
|
||||
buf.D = D; // X25519 u-coord
|
||||
buf.R = R; // X25519 u-coord
|
||||
buf.A = A; // Ed25519
|
||||
buf.B = B ? *B : zero;
|
||||
|
||||
cn_fast_hash(config::HASH_KEY_TXPROOF_V2,
|
||||
sizeof(config::HASH_KEY_TXPROOF_V2)-1,
|
||||
buf.sep);
|
||||
|
||||
//
|
||||
// 2. Compute X = ConvertPointE(k*G or k*B)
|
||||
//
|
||||
ge_p3 kB_or_kG_p3;
|
||||
if (B)
|
||||
ge_scalarmult_p3(&kB_or_kG_p3, &k, &B_p3);
|
||||
else
|
||||
ge_scalarmult_base(&kB_or_kG_p3, &k);
|
||||
|
||||
mx25519_pubkey X_x25519;
|
||||
ge_p3_to_x25519(X_x25519.data, &kB_or_kG_p3);
|
||||
memcpy(&buf.X, &X_x25519, sizeof(mx25519_pubkey));
|
||||
|
||||
//
|
||||
// 3. Compute Y = ConvertPointE(k*A)
|
||||
//
|
||||
ge_p3 kA_p3;
|
||||
ge_scalarmult_p3(&kA_p3, &k, &A_p3);
|
||||
|
||||
mx25519_pubkey Y_x25519;
|
||||
ge_p3_to_x25519(Y_x25519.data, &kA_p3);
|
||||
memcpy(&buf.Y, &Y_x25519, sizeof(mx25519_pubkey));
|
||||
|
||||
//
|
||||
// 4. Compute true Ed points R_ed_true and D_ed_true
|
||||
//
|
||||
ge_p3 R_ed_true, D_ed_true;
|
||||
|
||||
if (B)
|
||||
ge_scalarmult_p3(&R_ed_true, &r, &B_p3);
|
||||
else
|
||||
ge_scalarmult_base(&R_ed_true, &r);
|
||||
|
||||
ge_scalarmult_p3(&D_ed_true, &r, &A_p3);
|
||||
|
||||
//
|
||||
// 5. Determine sign bits for R and D
|
||||
//
|
||||
|
||||
// ---------- Extract and lift R ----------
|
||||
fe u_R;
|
||||
fe_frombytes_vartime(u_R, (const unsigned char *)&R);
|
||||
|
||||
fe v_R_cand;
|
||||
if (fe_sqrt_mont(v_R_cand, u_R) != 0)
|
||||
throw std::runtime_error("R not on curve");
|
||||
|
||||
fe x1, y1, x2, y2, v_R_neg, v_D_neg;
|
||||
mont_to_ed(x1, y1, u_R, v_R_cand);
|
||||
|
||||
fe_neg(v_R_neg, v_R_cand);
|
||||
mont_to_ed(x2, y2, u_R, v_R_neg);
|
||||
|
||||
// Compute affine Edwards coords of R_ed_true
|
||||
fe inv_z, xr_true, yr_true;
|
||||
fe_invert(inv_z, R_ed_true.Z);
|
||||
fe_mul(xr_true, R_ed_true.X, inv_z);
|
||||
fe_mul(yr_true, R_ed_true.Y, inv_z);
|
||||
|
||||
bool R_match1 = fe_equal(xr_true, x1) && fe_equal(yr_true, y1);
|
||||
bool R_match2 = fe_equal(xr_true, x2) && fe_equal(yr_true, y2);
|
||||
|
||||
if (!R_match1 && !R_match2)
|
||||
throw std::runtime_error("R mapping mismatch");
|
||||
|
||||
bool R_sign = R_match1;
|
||||
|
||||
// ---------- Extract and lift D ----------
|
||||
fe u_D;
|
||||
fe_frombytes_vartime(u_D, (const unsigned char *)&D);
|
||||
|
||||
fe v_D_cand;
|
||||
if (fe_sqrt_mont(v_D_cand, u_D) != 0)
|
||||
throw std::runtime_error("D not on curve");
|
||||
|
||||
mont_to_ed(x1, y1, u_D, v_D_cand);
|
||||
|
||||
fe_neg(v_D_neg, v_D_cand);
|
||||
mont_to_ed(x2, y2, u_D, v_D_neg);
|
||||
|
||||
fe_invert(inv_z, D_ed_true.Z);
|
||||
fe_mul(xr_true, D_ed_true.X, inv_z);
|
||||
fe_mul(yr_true, D_ed_true.Y, inv_z);
|
||||
|
||||
bool D_match1 = fe_equal(xr_true, x1) && fe_equal(yr_true, y1);
|
||||
bool D_match2 = fe_equal(xr_true, x2) && fe_equal(yr_true, y2);
|
||||
|
||||
if (!D_match1 && !D_match2)
|
||||
throw std::runtime_error("D mapping mismatch");
|
||||
|
||||
bool D_sign = D_match1;
|
||||
|
||||
//
|
||||
// 6. Pack sign bits into signature, include in challenge hash
|
||||
//
|
||||
sig.sign_mask =
|
||||
(R_sign ? 0x01 : 0x00) |
|
||||
(D_sign ? 0x02 : 0x00) |
|
||||
0x80;
|
||||
|
||||
struct {
|
||||
s_comm_2 buf;
|
||||
uint8_t sign_mask;
|
||||
} challenge_hash;
|
||||
|
||||
challenge_hash.buf = buf;
|
||||
challenge_hash.sign_mask = sig.sign_mask;
|
||||
|
||||
//
|
||||
// 7. Compute challenge c = H(prefix_hash || … || sign_mask)
|
||||
//
|
||||
hash_to_scalar(&challenge_hash, sizeof(challenge_hash), sig.c);
|
||||
|
||||
//
|
||||
// 8. Compute response z = k - c*r
|
||||
//
|
||||
sc_mulsub(&sig.r, &sig.c, &unwrap(r), &k);
|
||||
|
||||
memwipe(&k, sizeof(k));
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
bool ok = check_carrot_tx_proof(prefix_hash, R, A, B, D, sig);
|
||||
assert(ok);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Verify a proof: either v1 (version == 1) or v2 (version == 2)
|
||||
bool crypto_ops::check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig, const int version) {
|
||||
// sanity check
|
||||
@@ -608,6 +1004,167 @@ namespace crypto {
|
||||
return sc_isnonzero(&c2) == 0;
|
||||
}
|
||||
|
||||
// R and D are provided in X25519 format (u-coordinate), A and B in Ed25519.
|
||||
bool crypto_ops::check_carrot_tx_proof(
|
||||
const hash &prefix_hash,
|
||||
const public_key &R, // X25519 u
|
||||
const public_key &A, // Ed25519 viewkey
|
||||
const boost::optional<public_key> &B, // Ed25519 spendkey if any
|
||||
const public_key &D, // X25519 u
|
||||
const signature &sig)
|
||||
{
|
||||
ge_p3 A_p3, B_p3;
|
||||
if (ge_frombytes_vartime(&A_p3, &A) != 0)
|
||||
return false;
|
||||
if (B && ge_frombytes_vartime(&B_p3, &*B) != 0)
|
||||
return false;
|
||||
|
||||
if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0)
|
||||
return false;
|
||||
|
||||
// Extract sign bits and direction flag
|
||||
const bool R_sign = (sig.sign_mask & 0x01) != 0;
|
||||
const bool D_sign = (sig.sign_mask & 0x02) != 0;
|
||||
const bool outbound = (sig.sign_mask & 0x80) != 0;
|
||||
|
||||
//
|
||||
// 1. Reconstruct R_ed and D_ed from X25519 u-coords + sign bits
|
||||
//
|
||||
|
||||
// ----- R -----
|
||||
fe u_R, v_R_candidate, v_R;
|
||||
fe_frombytes_vartime(u_R, (const unsigned char *)&R);
|
||||
if (fe_sqrt_mont(v_R_candidate, u_R) != 0)
|
||||
return false;
|
||||
if (R_sign) fe_copy(v_R, v_R_candidate);
|
||||
else fe_neg(v_R, v_R_candidate);
|
||||
|
||||
fe x_R, y_R;
|
||||
mont_to_ed(x_R, y_R, u_R, v_R);
|
||||
ge_p3 R_ed;
|
||||
ge_from_xy(&R_ed, x_R, y_R); // Z=1, T=X*Y
|
||||
|
||||
// ----- D -----
|
||||
fe u_D, v_D_candidate, v_D;
|
||||
fe_frombytes_vartime(u_D, (const unsigned char *)&D);
|
||||
if (fe_sqrt_mont(v_D_candidate, u_D) != 0)
|
||||
return false;
|
||||
if (D_sign) fe_copy(v_D, v_D_candidate);
|
||||
else fe_neg(v_D, v_D_candidate);
|
||||
|
||||
fe x_D, y_D;
|
||||
mont_to_ed(x_D, y_D, u_D, v_D);
|
||||
ge_p3 D_ed;
|
||||
ge_from_xy(&D_ed, x_D, y_D);
|
||||
|
||||
//
|
||||
// 2. Compute X'
|
||||
// If inbound proof, X`= z*G + c*A (or z*B + c*A)
|
||||
// If outbound proof, X`= z*G + c*R_ed (or z*B + c*R_ed)
|
||||
//
|
||||
|
||||
ge_p3 c_p3;
|
||||
if (outbound)
|
||||
ge_scalarmult_p3(&c_p3, &sig.c, &R_ed);
|
||||
else
|
||||
ge_scalarmult_p3(&c_p3, &sig.c, &A_p3);
|
||||
|
||||
ge_p1p1 X_p1p1;
|
||||
if (B)
|
||||
{
|
||||
// Subaddress: X' = c*A + z*B
|
||||
ge_p3 rB_p3;
|
||||
ge_scalarmult_p3(&rB_p3, &sig.r, &B_p3);
|
||||
ge_cached rB_cached;
|
||||
ge_p3_to_cached(&rB_cached, &rB_p3);
|
||||
ge_add(&X_p1p1, &c_p3, &rB_cached);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Main address: X' = c*R_ed + z*G
|
||||
ge_p3 rG_p3;
|
||||
ge_scalarmult_base(&rG_p3, &sig.r);
|
||||
ge_cached rG_cached;
|
||||
ge_p3_to_cached(&rG_cached, &rG_p3);
|
||||
ge_add(&X_p1p1, &c_p3, &rG_cached);
|
||||
}
|
||||
|
||||
ge_p3 X_ed_p3;
|
||||
ge_p1p1_to_p3(&X_ed_p3, &X_p1p1);
|
||||
|
||||
mx25519_pubkey X_x25519;
|
||||
ge_p3_to_x25519(X_x25519.data, &X_ed_p3);
|
||||
|
||||
//
|
||||
// 3. Compute Y'
|
||||
// If inbound, Y' = c*D_ed + z*R
|
||||
// If outbound, Y' = c*D_ed + z*A
|
||||
//
|
||||
|
||||
ge_p3 cD_p3;
|
||||
ge_scalarmult_p3(&cD_p3, &sig.c, &D_ed);
|
||||
|
||||
ge_p3 z_p3;
|
||||
if (outbound)
|
||||
ge_scalarmult_p3(&z_p3, &sig.r, &A_p3);
|
||||
else
|
||||
ge_scalarmult_p3(&z_p3, &sig.r, &R_ed);
|
||||
|
||||
ge_cached z_cached;
|
||||
ge_p3_to_cached(&z_cached, &z_p3);
|
||||
|
||||
ge_p1p1 Y_p1p1;
|
||||
ge_add(&Y_p1p1, &cD_p3, &z_cached);
|
||||
|
||||
ge_p3 Y_ed_p3;
|
||||
ge_p1p1_to_p3(&Y_ed_p3, &Y_p1p1);
|
||||
|
||||
mx25519_pubkey Y_x25519;
|
||||
ge_p3_to_x25519(Y_x25519.data, &Y_ed_p3);
|
||||
|
||||
//
|
||||
// 4. Rebuild the hash transcript exactly as the prover did
|
||||
//
|
||||
|
||||
static const ec_point zero = {{
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||
}};
|
||||
|
||||
s_comm_2 buf;
|
||||
buf.msg = prefix_hash;
|
||||
buf.D = D; // X25519 (same bytes as prover)
|
||||
buf.R = R; // X25519
|
||||
buf.A = A; // Ed25519
|
||||
buf.B = B ? *B : zero;
|
||||
|
||||
cn_fast_hash(config::HASH_KEY_TXPROOF_V2,
|
||||
sizeof(config::HASH_KEY_TXPROOF_V2)-1,
|
||||
buf.sep);
|
||||
|
||||
memcpy(&buf.X, &X_x25519, sizeof(mx25519_pubkey));
|
||||
memcpy(&buf.Y, &Y_x25519, sizeof(mx25519_pubkey));
|
||||
|
||||
struct {
|
||||
s_comm_2 buf;
|
||||
uint8_t sign_mask;
|
||||
} challenge_hash;
|
||||
|
||||
challenge_hash.buf = buf;
|
||||
challenge_hash.sign_mask = sig.sign_mask;
|
||||
|
||||
//
|
||||
// 5. Recompute challenge and compare with sig.c
|
||||
//
|
||||
|
||||
ec_scalar c2;
|
||||
hash_to_scalar(&challenge_hash, sizeof(challenge_hash), c2);
|
||||
sc_sub(&c2, &c2, &sig.c);
|
||||
return sc_isnonzero(&c2) == 0;
|
||||
}
|
||||
|
||||
static void hash_to_ec(const public_key &key, ge_p3 &res) {
|
||||
hash h;
|
||||
ge_p2 point;
|
||||
@@ -796,4 +1353,4 @@ POP_WARNINGS
|
||||
ki.data[31] ^= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
-3
@@ -85,6 +85,7 @@ namespace crypto {
|
||||
|
||||
POD_CLASS signature {
|
||||
ec_scalar c, r;
|
||||
uint8_t sign_mask;
|
||||
friend class crypto_ops;
|
||||
};
|
||||
|
||||
@@ -99,7 +100,7 @@ namespace crypto {
|
||||
static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 &&
|
||||
sizeof(public_key) == 32 && sizeof(public_key_memsafe) == 32 && sizeof(secret_key) == 32 &&
|
||||
sizeof(key_derivation) == 32 && sizeof(key_image) == 32 && sizeof(key_image_y) == 32 &&
|
||||
sizeof(signature) == 64 && sizeof(view_tag) == 1, "Invalid structure size");
|
||||
sizeof(signature) == 65 && sizeof(view_tag) == 1, "Invalid structure size");
|
||||
|
||||
class crypto_ops {
|
||||
crypto_ops();
|
||||
@@ -131,8 +132,14 @@ namespace crypto {
|
||||
friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
static void generate_tx_proof_v1(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
friend void generate_tx_proof_v1(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
|
||||
static void generate_carrot_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, const secret_key &, signature &);
|
||||
friend void generate_carrot_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, const secret_key &, signature &);
|
||||
static void generate_carrot_tx_proof_as_sender(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, const secret_key &, signature &);
|
||||
friend void generate_carrot_tx_proof_as_sender(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, const secret_key &, signature &);
|
||||
static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &, const int);
|
||||
friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &, const int);
|
||||
static bool check_carrot_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
|
||||
friend bool check_carrot_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
|
||||
static void derive_key_image_generator(const public_key &, ec_point &);
|
||||
friend void derive_key_image_generator(const public_key &, ec_point &);
|
||||
static void generate_key_image(const public_key &, const secret_key &, key_image &);
|
||||
@@ -260,10 +267,28 @@ namespace crypto {
|
||||
inline void generate_tx_proof_v1(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
|
||||
crypto_ops::generate_tx_proof_v1(prefix_hash, R, A, B, D, r, sig);
|
||||
}
|
||||
/* Generation of a carrot tx proof; for carrot transactions, D is in X25519 domain (D = r*ConvertPointE(A))
|
||||
* instead of Ed25519 domain (D = r*A). This version applies ConvertPointE transformation.
|
||||
*/
|
||||
inline void generate_carrot_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, const secret_key &a, signature &sig) {
|
||||
crypto_ops::generate_carrot_tx_proof(prefix_hash, R, A, B, D, r, a, sig);
|
||||
}
|
||||
inline void generate_carrot_tx_proof_as_sender(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, const secret_key &a, signature &sig) {
|
||||
crypto_ops::generate_carrot_tx_proof_as_sender(prefix_hash, R, A, B, D, r, a, sig);
|
||||
}
|
||||
inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig, const int version) {
|
||||
return crypto_ops::check_tx_proof(prefix_hash, R, A, B, D, sig, version);
|
||||
}
|
||||
|
||||
/* Verification of a carrot tx proof; R and D should be in Ed25519 domain for verification,
|
||||
*/
|
||||
inline bool check_carrot_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
|
||||
return crypto_ops::check_carrot_tx_proof(prefix_hash, R, A, B, D, sig);
|
||||
}
|
||||
/*
|
||||
inline bool check_carrot_tx_proof_as_sender(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
|
||||
return crypto_ops::check_carrot_tx_proof_as_sender(prefix_hash, R, A, B, D, sig);
|
||||
}
|
||||
*/
|
||||
inline void derive_key_image_generator(const public_key &pub, ec_point &ki_gen) {
|
||||
crypto_ops::derive_key_image_generator(pub, ki_gen);
|
||||
}
|
||||
@@ -378,4 +403,4 @@ CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(public_key_memsafe)
|
||||
CRYPTO_MAKE_HASHABLE(key_image)
|
||||
CRYPTO_MAKE_HASHABLE(key_image_y)
|
||||
CRYPTO_MAKE_COMPARABLE(signature)
|
||||
CRYPTO_MAKE_COMPARABLE(view_tag)
|
||||
CRYPTO_MAKE_COMPARABLE(view_tag)
|
||||
|
||||
@@ -89,12 +89,24 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
void account_keys::xor_with_key_stream(const crypto::chacha_key &key)
|
||||
{
|
||||
// encrypt a large enough byte stream with chacha20
|
||||
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size()));
|
||||
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (8 + m_multisig_keys.size()));
|
||||
const char *ptr = key_stream.data();
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_spend_secret_key.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_view_secret_key.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
s_master.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
k_prove_spend.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
s_view_balance.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
k_view_incoming.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
k_generate_image.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
s_generate_address.data[i] ^= *ptr++;
|
||||
for (crypto::secret_key &k: m_multisig_keys)
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
@@ -116,11 +128,20 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
void account_keys::encrypt_viewkey(const crypto::chacha_key &key)
|
||||
{
|
||||
// encrypt a large enough byte stream with chacha20
|
||||
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * 2);
|
||||
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * 8);
|
||||
const char *ptr = key_stream.data();
|
||||
ptr += sizeof(crypto::secret_key);
|
||||
ptr += sizeof(crypto::secret_key); // Skip m_spend_secret_key
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
m_view_secret_key.data[i] ^= *ptr++;
|
||||
ptr += (2 * sizeof(crypto::secret_key)); // Skip s_master, k_prove_spend
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
s_view_balance.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
k_view_incoming.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
k_generate_image.data[i] ^= *ptr++;
|
||||
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
|
||||
s_generate_address.data[i] ^= *ptr++;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
void account_keys::decrypt_viewkey(const crypto::chacha_key &key)
|
||||
@@ -151,6 +172,8 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
void account_base::forget_spend_key()
|
||||
{
|
||||
m_keys.m_spend_secret_key = crypto::secret_key();
|
||||
m_keys.s_master = m_keys.m_spend_secret_key;
|
||||
m_keys.k_prove_spend = m_keys.m_spend_secret_key;
|
||||
m_keys.m_multisig_keys.clear();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
@@ -163,6 +186,7 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
"Unexpected derived public spend key");
|
||||
|
||||
m_keys.m_spend_secret_key = spend_secret_key;
|
||||
m_keys.s_master = m_keys.m_spend_secret_key;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
|
||||
@@ -276,6 +300,14 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
//TODO: change this code into base 58
|
||||
return get_account_address_as_str(nettype, false, m_keys.m_account_address);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
std::string account_base::get_carrot_public_address_str(network_type nettype) const
|
||||
{
|
||||
// Build the cryptonote::account_public_address
|
||||
account_public_address addr{m_keys.m_carrot_main_address.m_spend_public_key, m_keys.m_carrot_main_address.m_view_public_key, true};
|
||||
// change this code into base 58
|
||||
return get_account_address_as_str(nettype, false, addr);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, network_type nettype) const
|
||||
{
|
||||
|
||||
@@ -57,12 +57,16 @@ namespace cryptonote
|
||||
crypto::secret_key s_master;
|
||||
crypto::secret_key k_prove_spend;
|
||||
crypto::secret_key s_view_balance;
|
||||
crypto::secret_key k_view_incoming;
|
||||
crypto::secret_key k_generate_image;
|
||||
crypto::secret_key s_generate_address;
|
||||
|
||||
// carrot public keys (minus K^0_v, which is shared with legacy K^0_v)
|
||||
crypto::public_key carrot_account_spend_pubkey;
|
||||
crypto::public_key carrot_account_view_pubkey;
|
||||
// carrot public account address (K_s, K_v)
|
||||
account_public_address m_carrot_account_address;
|
||||
|
||||
// carrot main address (K^0_s, K^0_v)
|
||||
account_public_address m_carrot_main_address;
|
||||
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(m_account_address)
|
||||
@@ -71,6 +75,11 @@ namespace cryptonote
|
||||
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys)
|
||||
const crypto::chacha_iv default_iv{{0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv)
|
||||
if (m_account_address.m_spend_public_key == crypto::null_pkey) {
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(s_view_balance)
|
||||
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(k_view_incoming)
|
||||
KV_SERIALIZE(m_carrot_account_address)
|
||||
}
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
void encrypt(const crypto::chacha_key &key);
|
||||
@@ -100,6 +109,7 @@ namespace cryptonote
|
||||
bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys);
|
||||
const account_keys& get_keys() const;
|
||||
std::string get_public_address_str(network_type nettype) const;
|
||||
std::string get_carrot_public_address_str(network_type nettype) const;
|
||||
std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, network_type nettype) const;
|
||||
|
||||
hw::device& get_device() const {return m_keys.get_device();}
|
||||
@@ -135,7 +145,8 @@ namespace cryptonote
|
||||
|
||||
private:
|
||||
void set_null();
|
||||
account_keys m_keys;
|
||||
protected:
|
||||
uint64_t m_creation_timestamp;
|
||||
account_keys m_keys;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "serialization/debug_archive.h"
|
||||
#include "serialization/crypto.h"
|
||||
#include "serialization/keyvalue_serialization.h" // eepe named serialization
|
||||
#include "serialization/pair.h"
|
||||
#include "serialization/string.h"
|
||||
#include "carrot_core/core_types.h"
|
||||
#include "carrot_impl/carrot_chain_serialization.h"
|
||||
@@ -193,8 +194,116 @@ namespace cryptonote
|
||||
VARINT_FIELD(amount)
|
||||
FIELD(target)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
class protocol_tx_data_t {
|
||||
public:
|
||||
uint8_t version;
|
||||
crypto::public_key return_address;
|
||||
crypto::public_key return_pubkey;
|
||||
carrot::view_tag_t return_view_tag;
|
||||
carrot::encrypted_janus_anchor_t return_anchor_enc;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(version)
|
||||
FIELD(return_address)
|
||||
FIELD(return_pubkey)
|
||||
FIELD(return_view_tag)
|
||||
FIELD(return_anchor_enc)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct erc_token_t
|
||||
{
|
||||
uint8_t version;
|
||||
std::string contract_address;
|
||||
std::string lockbox_address;
|
||||
std::string ticker;
|
||||
uint64_t erc20_asset_id; // NOTE: this is NOT the Salvium `asset_type_id`!!!
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(version)
|
||||
FIELD(contract_address)
|
||||
FIELD(lockbox_address)
|
||||
FIELD(ticker)
|
||||
VARINT_FIELD(erc20_asset_id)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(contract_address)
|
||||
KV_SERIALIZE(lockbox_address)
|
||||
KV_SERIALIZE(ticker)
|
||||
KV_SERIALIZE(erc20_asset_id)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct sal_token_t
|
||||
{
|
||||
uint8_t version;
|
||||
uint64_t supply;
|
||||
uint64_t size;
|
||||
std::string name;
|
||||
std::string url;
|
||||
crypto::hash signature;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(version)
|
||||
VARINT_FIELD(supply)
|
||||
VARINT_FIELD(size)
|
||||
FIELD(name)
|
||||
FIELD(url)
|
||||
FIELD(signature)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(supply)
|
||||
KV_SERIALIZE(size)
|
||||
KV_SERIALIZE(name)
|
||||
KV_SERIALIZE(url)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
#define TOKEN_TYPE_UNSET 0
|
||||
#define TOKEN_TYPE_ERC20 1
|
||||
#define TOKEN_TYPE_SAL 2
|
||||
|
||||
typedef boost::variant<erc_token_t, sal_token_t> token_v;
|
||||
|
||||
struct token_metadata_t
|
||||
{
|
||||
uint8_t version;
|
||||
std::string asset_type;
|
||||
token_v token;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(version)
|
||||
FIELD(asset_type)
|
||||
FIELD(token)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
class layer2_rollup_tx_t {
|
||||
public:
|
||||
crypto::hash tx_prefix_hash;
|
||||
crypto::key_image first_key_image;
|
||||
uint64_t tx_fee;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(tx_prefix_hash)
|
||||
FIELD(first_key_image)
|
||||
VARINT_FIELD(tx_fee)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
class layer2_rollup_data_t {
|
||||
public:
|
||||
uint8_t version;
|
||||
std::vector<layer2_rollup_tx_t> txs;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VARINT_FIELD(version)
|
||||
FIELD(txs)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
class transaction_prefix
|
||||
@@ -227,6 +336,12 @@ namespace cryptonote
|
||||
// Slippage limit
|
||||
uint64_t amount_slippage_limit;
|
||||
|
||||
protocol_tx_data_t protocol_tx_data;
|
||||
|
||||
carrot::rollup_binding_tag_t rollup_binding_tag;
|
||||
token_metadata_t token_metadata;
|
||||
layer2_rollup_data_t layer2_rollup_data;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(version)
|
||||
if(version == 0 || CURRENT_TRANSACTION_VERSION < version) return false;
|
||||
@@ -244,14 +359,30 @@ namespace cryptonote
|
||||
FIELD(return_address_list)
|
||||
FIELD(return_address_change_mask)
|
||||
} else {
|
||||
FIELD(return_address)
|
||||
FIELD(return_pubkey)
|
||||
if ((type == cryptonote::transaction_type::STAKE || type == cryptonote::transaction_type::CREATE_TOKEN) &&
|
||||
(version >= TRANSACTION_VERSION_CARROT)) {
|
||||
FIELD(protocol_tx_data)
|
||||
} else {
|
||||
FIELD(return_address)
|
||||
FIELD(return_pubkey)
|
||||
}
|
||||
}
|
||||
FIELD(source_asset_type)
|
||||
FIELD(destination_asset_type)
|
||||
VARINT_FIELD(amount_slippage_limit)
|
||||
}
|
||||
}
|
||||
if (version < TRANSACTION_VERSION_ENABLE_TOKENS) {
|
||||
return true;
|
||||
}
|
||||
if (type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
FIELD(token_metadata)
|
||||
} else if (type == cryptonote::transaction_type::TRANSFER) {
|
||||
FIELD(rollup_binding_tag)
|
||||
} else if (type == cryptonote::transaction_type::ROLLUP) {
|
||||
FIELD(rollup_binding_tag)
|
||||
FIELD(layer2_rollup_data)
|
||||
}
|
||||
END_SERIALIZE()
|
||||
|
||||
public:
|
||||
@@ -268,10 +399,18 @@ namespace cryptonote
|
||||
return_address_list.clear();
|
||||
return_address_change_mask.clear();
|
||||
return_pubkey = crypto::null_pkey;
|
||||
protocol_tx_data.return_address = crypto::null_pkey;
|
||||
protocol_tx_data.return_pubkey = crypto::null_pkey;
|
||||
protocol_tx_data.return_view_tag = {};
|
||||
protocol_tx_data.return_anchor_enc = {};
|
||||
token_metadata.version = 0;
|
||||
source_asset_type.clear();
|
||||
destination_asset_type.clear();
|
||||
amount_burnt = 0;
|
||||
amount_slippage_limit = 0;
|
||||
rollup_binding_tag = {0};
|
||||
token_metadata = {};
|
||||
layer2_rollup_data = {};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -535,6 +674,91 @@ namespace cryptonote
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct token_block_info {
|
||||
uint64_t block_height;
|
||||
std::map<uint32_t, uint64_t> token_info; // Replaces the vector
|
||||
|
||||
token_block_info() = default; // default ctor
|
||||
|
||||
explicit token_block_info(const uint64_t h)
|
||||
: block_height(h) {}
|
||||
|
||||
void clear() {
|
||||
block_height = 0;
|
||||
token_info.clear();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> serialize() const noexcept {
|
||||
constexpr uint8_t version = 1; // Bump if format changes
|
||||
uint32_t sz = static_cast<uint32_t>(token_info.size());
|
||||
size_t total_size = sizeof(uint8_t) + sizeof(uint64_t) + sizeof(uint32_t) + (sz * (sizeof(uint32_t) + sizeof(uint64_t)));
|
||||
std::vector<uint8_t> buf(total_size);
|
||||
uint8_t* ptr = buf.data();
|
||||
|
||||
std::memcpy(ptr, &version, sizeof(uint8_t));
|
||||
ptr += sizeof(uint8_t);
|
||||
|
||||
std::memcpy(ptr, &block_height, sizeof(uint64_t));
|
||||
ptr += sizeof(uint64_t);
|
||||
|
||||
std::memcpy(ptr, &sz, sizeof(uint32_t));
|
||||
ptr += sizeof(uint32_t);
|
||||
|
||||
for (const auto& p : token_info) { // Iterates in sorted order
|
||||
std::memcpy(ptr, &p.first, sizeof(uint32_t));
|
||||
ptr += sizeof(uint32_t);
|
||||
std::memcpy(ptr, &p.second, sizeof(uint64_t));
|
||||
ptr += sizeof(uint64_t);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void deserialize(const uint8_t* data, size_t len) {
|
||||
if (len < sizeof(uint32_t)) {
|
||||
throw std::runtime_error("Invalid serialized data");
|
||||
}
|
||||
|
||||
uint8_t version;
|
||||
std::memcpy(&version, data, sizeof(uint8_t));
|
||||
data += sizeof(uint8_t);
|
||||
len -= sizeof(uint8_t);
|
||||
|
||||
if (version == 0) { // Legacy: No height/version (your current format)
|
||||
// Handle old blobs: Caller must set block_height externally
|
||||
block_height = 0; // Or throw if height is mandatory
|
||||
} else if (version == 1) {
|
||||
if (len < sizeof(uint64_t) + sizeof(uint32_t)) {
|
||||
throw std::runtime_error("Invalid serialized data");
|
||||
}
|
||||
std::memcpy(&block_height, data, sizeof(uint64_t));
|
||||
data += sizeof(uint64_t);
|
||||
len -= sizeof(uint64_t);
|
||||
} else {
|
||||
throw std::runtime_error("Unsupported version");
|
||||
}
|
||||
|
||||
uint32_t sz;
|
||||
std::memcpy(&sz, data, sizeof(uint32_t));
|
||||
data += sizeof(uint32_t);
|
||||
len -= sizeof(uint32_t);
|
||||
|
||||
if (len != sz * (sizeof(uint32_t) + sizeof(uint64_t))) {
|
||||
throw std::runtime_error("Invalid serialized data length");
|
||||
}
|
||||
|
||||
token_info.clear();
|
||||
for (uint32_t i = 0; i < sz; ++i) {
|
||||
uint32_t k;
|
||||
uint64_t v;
|
||||
std::memcpy(&k, data, sizeof(uint32_t));
|
||||
data += sizeof(uint32_t);
|
||||
std::memcpy(&v, data, sizeof(uint64_t));
|
||||
data += sizeof(uint64_t);
|
||||
token_info[k] = v; // Map handles sorting/uniquness
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct yield_block_info {
|
||||
uint64_t block_height;
|
||||
uint64_t slippage_total_this_block;
|
||||
@@ -669,6 +893,7 @@ namespace cryptonote
|
||||
{
|
||||
crypto::public_key m_spend_public_key;
|
||||
crypto::public_key m_view_public_key;
|
||||
bool m_is_carrot;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(m_spend_public_key)
|
||||
@@ -683,7 +908,8 @@ namespace cryptonote
|
||||
bool operator==(const account_public_address& rhs) const
|
||||
{
|
||||
return m_spend_public_key == rhs.m_spend_public_key &&
|
||||
m_view_public_key == rhs.m_view_public_key;
|
||||
m_view_public_key == rhs.m_view_public_key &&
|
||||
m_is_carrot == rhs.m_is_carrot;
|
||||
}
|
||||
|
||||
bool operator!=(const account_public_address& rhs) const
|
||||
@@ -752,6 +978,10 @@ VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_tagged_key, 0x3);
|
||||
VARIANT_TAG(binary_archive, cryptonote::txout_to_carrot_v1, 0x4);
|
||||
VARIANT_TAG(binary_archive, cryptonote::protocol_tx_data_t, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::token_metadata_t, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::erc_token_t, 0x0);
|
||||
VARIANT_TAG(binary_archive, cryptonote::sal_token_t, 0x1);
|
||||
VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
|
||||
VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
|
||||
|
||||
@@ -764,6 +994,10 @@ VARIANT_TAG(json_archive, cryptonote::txout_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_key, "key");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_tagged_key, "tagged_key");
|
||||
VARIANT_TAG(json_archive, cryptonote::txout_to_carrot_v1, "carrot_v1");
|
||||
VARIANT_TAG(json_archive, cryptonote::protocol_tx_data_t, "protocol_tx_data");
|
||||
VARIANT_TAG(json_archive, cryptonote::token_metadata_t, "token_metadata");
|
||||
VARIANT_TAG(json_archive, cryptonote::erc_token_t, "erc_token");
|
||||
VARIANT_TAG(json_archive, cryptonote::sal_token_t, "sal_token");
|
||||
VARIANT_TAG(json_archive, cryptonote::transaction, "tx");
|
||||
VARIANT_TAG(json_archive, cryptonote::block, "block");
|
||||
|
||||
@@ -776,5 +1010,9 @@ VARIANT_TAG(debug_archive, cryptonote::txout_to_scripthash, "scripthash");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_key, "key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_tagged_key, "tagged_key");
|
||||
VARIANT_TAG(debug_archive, cryptonote::txout_to_carrot_v1, "carrot_v1");
|
||||
VARIANT_TAG(debug_archive, cryptonote::protocol_tx_data_t, "protocol_tx_data");
|
||||
VARIANT_TAG(debug_archive, cryptonote::token_metadata_t, "token_metadata");
|
||||
VARIANT_TAG(debug_archive, cryptonote::erc_token_t, "erc_token");
|
||||
VARIANT_TAG(debug_archive, cryptonote::sal_token_t, "sal_token");
|
||||
VARIANT_TAG(debug_archive, cryptonote::transaction, "tx");
|
||||
VARIANT_TAG(debug_archive, cryptonote::block, "block");
|
||||
|
||||
@@ -157,7 +157,9 @@ namespace cryptonote {
|
||||
, account_public_address const & adr
|
||||
)
|
||||
{
|
||||
uint64_t address_prefix = subaddress ? get_config(nettype).CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : get_config(nettype).CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t address_prefix = adr.m_is_carrot
|
||||
? (subaddress ? get_config(nettype).CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX : get_config(nettype).CARROT_PUBLIC_ADDRESS_BASE58_PREFIX)
|
||||
: (subaddress ? get_config(nettype).CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX : get_config(nettype).CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX);
|
||||
|
||||
return tools::base58::encode_addr(address_prefix, t_serializable_object_to_blob(adr));
|
||||
}
|
||||
@@ -168,7 +170,7 @@ namespace cryptonote {
|
||||
, crypto::hash8 const & payment_id
|
||||
)
|
||||
{
|
||||
uint64_t integrated_address_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t integrated_address_prefix = adr.m_is_carrot ? get_config(nettype).CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : get_config(nettype).CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||
|
||||
integrated_address iadr = {
|
||||
adr, payment_id
|
||||
@@ -196,6 +198,9 @@ namespace cryptonote {
|
||||
uint64_t address_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t integrated_address_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t subaddress_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX;
|
||||
uint64_t carrot_address_prefix = get_config(nettype).CARROT_PUBLIC_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t carrot_integrated_address_prefix = get_config(nettype).CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t carrot_subaddress_prefix = get_config(nettype).CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX;
|
||||
|
||||
if (2 * sizeof(public_address_outer_blob) != str.size())
|
||||
{
|
||||
@@ -211,21 +216,45 @@ namespace cryptonote {
|
||||
{
|
||||
info.is_subaddress = false;
|
||||
info.has_payment_id = true;
|
||||
info.is_carrot = false;
|
||||
}
|
||||
else if (address_prefix == prefix)
|
||||
{
|
||||
info.is_subaddress = false;
|
||||
info.has_payment_id = false;
|
||||
info.is_carrot = false;
|
||||
}
|
||||
else if (subaddress_prefix == prefix)
|
||||
{
|
||||
info.is_subaddress = true;
|
||||
info.has_payment_id = false;
|
||||
info.is_carrot = false;
|
||||
}
|
||||
else if (carrot_integrated_address_prefix == prefix)
|
||||
{
|
||||
info.is_subaddress = false;
|
||||
info.has_payment_id = true;
|
||||
info.is_carrot = true;
|
||||
}
|
||||
else if (carrot_address_prefix == prefix)
|
||||
{
|
||||
info.is_subaddress = false;
|
||||
info.has_payment_id = false;
|
||||
info.is_carrot = true;
|
||||
}
|
||||
else if (carrot_subaddress_prefix == prefix)
|
||||
{
|
||||
info.is_subaddress = true;
|
||||
info.has_payment_id = false;
|
||||
info.is_carrot = true;
|
||||
}
|
||||
else {
|
||||
LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << address_prefix
|
||||
<< " or " << integrated_address_prefix
|
||||
<< " or " << subaddress_prefix);
|
||||
<< " or " << subaddress_prefix
|
||||
<< " or " << carrot_address_prefix
|
||||
<< " or " << carrot_integrated_address_prefix
|
||||
<< " or " << carrot_subaddress_prefix);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -254,6 +283,8 @@ namespace cryptonote {
|
||||
LOG_PRINT_L1("Failed to validate address keys");
|
||||
return false;
|
||||
}
|
||||
|
||||
info.address.m_is_carrot = info.is_carrot;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -285,8 +316,10 @@ namespace cryptonote {
|
||||
|
||||
//we success
|
||||
info.address = blob.m_address;
|
||||
info.address.m_is_carrot = false;
|
||||
info.is_subaddress = false;
|
||||
info.has_payment_id = false;
|
||||
info.is_carrot = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace cryptonote {
|
||||
account_public_address address;
|
||||
bool is_subaddress;
|
||||
bool has_payment_id;
|
||||
bool is_carrot;
|
||||
crypto::hash8 payment_id;
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include "crypto/crypto.h"
|
||||
#include "ringct/rctTypes.h"
|
||||
#include "ringct/rctOps.h"
|
||||
#include "serialization/containers.h"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -73,6 +74,11 @@ namespace boost
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, carrot::input_context_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(carrot::input_context_t)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::view_tag &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::view_tag)]>(x);
|
||||
@@ -166,6 +172,59 @@ namespace boost
|
||||
a & x.target;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::protocol_tx_data_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
a & x.return_view_tag;
|
||||
a & x.return_anchor_enc;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::erc_token_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.contract_address;
|
||||
a & x.lockbox_address;
|
||||
a & x.ticker;
|
||||
a & x.erc20_asset_id;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::sal_token_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.supply;
|
||||
a & x.size;
|
||||
a & x.name;
|
||||
a & x.url;
|
||||
a & x.signature;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::token_metadata_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.asset_type;
|
||||
a & x.token;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::layer2_rollup_tx_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.tx_prefix_hash;
|
||||
a & x.first_key_image;
|
||||
a & x.tx_fee;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::layer2_rollup_data_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.version;
|
||||
a & x.txs;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, cryptonote::transaction_prefix &x, const boost::serialization::version_type ver)
|
||||
@@ -183,14 +242,29 @@ namespace boost
|
||||
a & x.return_address_list;
|
||||
a & x.return_address_change_mask;
|
||||
} else {
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
if ((x.type == cryptonote::transaction_type::STAKE || x.type == cryptonote::transaction_type::CREATE_TOKEN) &&
|
||||
(x.version >= TRANSACTION_VERSION_CARROT)) {
|
||||
a & x.protocol_tx_data;
|
||||
} else {
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
}
|
||||
}
|
||||
a & x.source_asset_type;
|
||||
a & x.destination_asset_type;
|
||||
a & x.amount_slippage_limit;
|
||||
}
|
||||
}
|
||||
if (x.version >= TRANSACTION_VERSION_ENABLE_TOKENS) {
|
||||
if (x.type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
a & x.token_metadata;
|
||||
} else if (x.type == cryptonote::transaction_type::TRANSFER) {
|
||||
a & x.rollup_binding_tag;
|
||||
} else if (x.type == cryptonote::transaction_type::ROLLUP) {
|
||||
a & x.rollup_binding_tag;
|
||||
a & x.layer2_rollup_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
@@ -209,13 +283,28 @@ namespace boost
|
||||
a & x.return_address_list;
|
||||
a & x.return_address_change_mask;
|
||||
} else {
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
if ((x.type == cryptonote::transaction_type::STAKE || x.type == cryptonote::transaction_type::CREATE_TOKEN) &&
|
||||
(x.version >= TRANSACTION_VERSION_CARROT)) {
|
||||
a & x.protocol_tx_data;
|
||||
} else {
|
||||
a & x.return_address;
|
||||
a & x.return_pubkey;
|
||||
}
|
||||
}
|
||||
a & x.source_asset_type;
|
||||
a & x.destination_asset_type;
|
||||
a & x.amount_slippage_limit;
|
||||
}
|
||||
if (x.version >= TRANSACTION_VERSION_ENABLE_TOKENS) {
|
||||
if (x.type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
a & x.token_metadata;
|
||||
} else if (x.type == cryptonote::transaction_type::TRANSFER) {
|
||||
a & x.rollup_binding_tag;
|
||||
} else if (x.type == cryptonote::transaction_type::ROLLUP) {
|
||||
a & x.rollup_binding_tag;
|
||||
a & x.layer2_rollup_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x.version == 1)
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <csignal>
|
||||
#include <map>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "wipeable_string.h"
|
||||
#include "string_tools.h"
|
||||
@@ -43,6 +44,7 @@
|
||||
#include "crypto/hash.h"
|
||||
#include "ringct/rctSigs.h"
|
||||
#include "oracle/asset_types.h"
|
||||
#include "common/debugging.h"
|
||||
|
||||
using namespace epee;
|
||||
|
||||
@@ -113,7 +115,7 @@ namespace cryptonote
|
||||
const bool plus = (
|
||||
rv.type == rct::RCTTypeBulletproofPlus ||
|
||||
rv.type == rct::RCTTypeFullProofs ||
|
||||
rv.type == rct::RCTTypeSalviumZero ||
|
||||
/*rv.type == rct::RCTTypeSalviumZero ||*/
|
||||
rv.type == rct::RCTTypeSalviumOne);
|
||||
const uint64_t bp_base = (32 * ((plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
|
||||
const size_t n_outputs = tx.vout.size();
|
||||
@@ -646,7 +648,7 @@ namespace cryptonote
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(tx.pruned, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support non pruned txes");
|
||||
CHECK_AND_ASSERT_MES(tx.version >= 2, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support v1 txes");
|
||||
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs,
|
||||
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs || tx.rct_signatures.type == rct::RCTTypeSalviumZero || tx.rct_signatures.type == rct::RCTTypeSalviumOne,
|
||||
std::numeric_limits<uint64_t>::max(), "Unsupported rct_signatures type in get_pruned_transaction_weight");
|
||||
CHECK_AND_ASSERT_MES(!tx.vin.empty(), std::numeric_limits<uint64_t>::max(), "empty vin");
|
||||
CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), std::numeric_limits<uint64_t>::max(), "empty vin");
|
||||
@@ -1114,7 +1116,37 @@ namespace cryptonote
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (asset_type_id)
|
||||
{
|
||||
// Check to see if 1st byte is permitted
|
||||
std::string s, s_prefix;
|
||||
switch (asset_type_id >> 24) {
|
||||
case 0x01:
|
||||
// We have a user-generated token
|
||||
s_prefix = "sal";
|
||||
break;
|
||||
case 0x02:
|
||||
s_prefix = "erc";
|
||||
break;
|
||||
default:
|
||||
ASSERT_MES_AND_THROW("Invalid asset_type_id: " << asset_type_id);
|
||||
}
|
||||
|
||||
// Break up the remaining 3 bytes into 4 chunks of base36/64
|
||||
static const char alphabet[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
uint32_t asset_type_id_temp = asset_type_id & 0x00FFFFFF;
|
||||
for (int i=0; i<4; ++i) {
|
||||
uint8_t val = asset_type_id_temp & 0x0000003F;
|
||||
if (val >= 36)
|
||||
ASSERT_MES_AND_THROW("Invalid asset_type_id: " << asset_type_id);
|
||||
s.push_back(alphabet[val]);
|
||||
asset_type_id_temp >>= 6;
|
||||
}
|
||||
std::reverse(s.begin(), s.end());
|
||||
return s_prefix + s;
|
||||
}
|
||||
// Should probably throw() here
|
||||
ASSERT_MES_AND_THROW("Invalid asset_type_id: " << asset_type_id);
|
||||
return "";
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
@@ -1129,11 +1161,162 @@ namespace cryptonote
|
||||
} else if (asset_type == "") {
|
||||
return 0x00000000;
|
||||
} else {
|
||||
// Should probably throw() here
|
||||
return static_cast<uint32_t>(-1);
|
||||
if (asset_type.length() != 7) {
|
||||
LOG_ERROR("Custom asset type '" << asset_type << "' has invalid length.");
|
||||
return 0x00000000;
|
||||
}
|
||||
static const std::string alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
// Check the 4-char type
|
||||
std::string s_type = asset_type.substr(3);
|
||||
std::transform(s_type.begin(), s_type.end(), s_type.begin(),
|
||||
[](unsigned char c){ return std::toupper(c); });
|
||||
uint32_t asset_id = 0x00000000;
|
||||
for (int i=0; i<s_type.length(); ++i) {
|
||||
uint8_t idx = alphabet.find(s_type.at(i));
|
||||
if (idx == std::string::npos || idx >= 36) {
|
||||
LOG_ERROR("Custom asset type contains invalid char.");
|
||||
return 0x00000000;
|
||||
}
|
||||
asset_id = (asset_id << 6) | (idx & 0x3F);
|
||||
}
|
||||
|
||||
// Check the 3-char prefix
|
||||
std::string s_prefix = asset_type.substr(0,3);
|
||||
std::transform(s_prefix.begin(), s_prefix.end(), s_prefix.begin(),
|
||||
[](unsigned char c){ return std::tolower(c); });
|
||||
if (s_prefix == "sal") {
|
||||
asset_id |= 0x01000000;
|
||||
} else if (s_prefix == "erc") {
|
||||
asset_id |= 0x02000000;
|
||||
} else {
|
||||
LOG_ERROR("Custom asset type has invalid prefix.");
|
||||
return 0x00000000;
|
||||
}
|
||||
return asset_id;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_asset_type_token(const std::string& asset_type)
|
||||
{
|
||||
// SAL, SAL1, BURN are base asset types
|
||||
// erc prefix is not included here
|
||||
if (asset_type.length() >= 3) {
|
||||
std::string prefix = asset_type.substr(0, 3);
|
||||
return (prefix == "sal");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_valid_asset_type(const std::string& asset_type) {
|
||||
// This method does NOT throw()
|
||||
try {
|
||||
uint32_t asset_id = asset_id_from_type(asset_type);
|
||||
std::string asset_type_check = asset_type_from_id(asset_id);
|
||||
return (asset_type_check == asset_type);
|
||||
}
|
||||
catch (std::exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool is_valid_custom_asset_type(const std::string& asset_type)
|
||||
{
|
||||
if (!is_valid_asset_type(asset_type))
|
||||
return false;
|
||||
|
||||
// double check with reserved IDs
|
||||
uint32_t id = asset_id_from_type(asset_type);
|
||||
if (id == 0x53414C00 || id == 0x53414C31 || id == 0x4255524E || id == 0x00000000) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
uint64_t get_token_creation_price(const std::string& ticker)
|
||||
{
|
||||
static const std::map<std::string, uint64_t> premium_tickers = {
|
||||
// add more
|
||||
{"USDT", 10000 * COIN},
|
||||
{"USDC", 10000 * COIN},
|
||||
{"WBTC", 10000 * COIN},
|
||||
{"DOGE", 10000 * COIN},
|
||||
{"SHIB", 10000 * COIN},
|
||||
{"AVAX", 10000 * COIN},
|
||||
{"ATOM", 10000 * COIN},
|
||||
{"NEAR", 10000 * COIN},
|
||||
{"TRON", 10000 * COIN},
|
||||
{"HBAR", 10000 * COIN},
|
||||
{"AAVE", 10000 * COIN},
|
||||
{"FLOW", 10000 * COIN},
|
||||
{"EGLD", 10000 * COIN},
|
||||
{"KLAY", 10000 * COIN},
|
||||
{"LUNA", 10000 * COIN},
|
||||
{"DASH", 10000 * COIN},
|
||||
{"NANO", 10000 * COIN},
|
||||
{"CORE", 10000 * COIN},
|
||||
{"BEAM", 10000 * COIN},
|
||||
{"DYDX", 10000 * COIN},
|
||||
{"COMP", 10000 * COIN},
|
||||
{"SAND", 10000 * COIN},
|
||||
{"MANA", 10000 * COIN},
|
||||
{"RUNE", 10000 * COIN},
|
||||
{"PYTH", 10000 * COIN},
|
||||
{"ARKM", 10000 * COIN},
|
||||
{"BLUR", 10000 * COIN},
|
||||
{"STRK", 10000 * COIN},
|
||||
{"PEPE", 10000 * COIN},
|
||||
{"BONK", 10000 * COIN},
|
||||
{"VIUM", 10000 * COIN},
|
||||
{"GOLD", 10000 * COIN},
|
||||
{"SILV", 10000 * COIN},
|
||||
{"CASH", 10000 * COIN},
|
||||
{"EURO", 10000 * COIN},
|
||||
{"PESO", 10000 * COIN},
|
||||
{"BOND", 10000 * COIN},
|
||||
{"FUND", 10000 * COIN},
|
||||
{"BANK", 10000 * COIN},
|
||||
{"SWAP", 10000 * COIN},
|
||||
{"LEND", 10000 * COIN},
|
||||
{"LOAN", 10000 * COIN},
|
||||
{"NOTE", 10000 * COIN},
|
||||
{"HOLD", 10000 * COIN},
|
||||
{"BULL", 10000 * COIN},
|
||||
{"BEAR", 10000 * COIN},
|
||||
{"TECH", 10000 * COIN},
|
||||
{"DATA", 10000 * COIN},
|
||||
{"HASH", 10000 * COIN},
|
||||
{"NODE", 10000 * COIN},
|
||||
{"BYTE", 10000 * COIN},
|
||||
{"GRID", 10000 * COIN},
|
||||
{"CODE", 10000 * COIN},
|
||||
{"META", 10000 * COIN},
|
||||
{"WEB3", 10000 * COIN},
|
||||
{"NFTS", 10000 * COIN},
|
||||
{"DEFI", 10000 * COIN},
|
||||
{"LAND", 10000 * COIN},
|
||||
{"REAL", 10000 * COIN},
|
||||
{"RENT", 10000 * COIN},
|
||||
{"FARM", 10000 * COIN},
|
||||
{"OILX", 10000 * COIN},
|
||||
{"ENRG", 10000 * COIN},
|
||||
{"FUEL", 10000 * COIN},
|
||||
{"VOTE", 10000 * COIN},
|
||||
{"PASS", 10000 * COIN},
|
||||
{"LOCK", 10000 * COIN},
|
||||
};
|
||||
|
||||
// is it a premium ticker
|
||||
auto it = premium_tickers.find(ticker);
|
||||
if (it != premium_tickers.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// not premium
|
||||
return 1000 * COIN;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
/**
|
||||
* The various scenarios that are permitted for Salvium are more extensive than
|
||||
* they are for Zepyhr / Havan. Specifically, we permit:
|
||||
@@ -1381,48 +1564,31 @@ namespace cryptonote
|
||||
|
||||
for (const auto &o: tx.vout)
|
||||
{
|
||||
if (hf_version >= HF_VERSION_CARROT)
|
||||
{
|
||||
// from v11, require outputs be carrot outputs
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx));
|
||||
} else {
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
if (tx.type != cryptonote::transaction_type::PROTOCOL) {
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx));
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) ||
|
||||
o.target.type() == typeid(txout_to_tagged_key) ||
|
||||
o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key or txout_to_carrot_v1 in protocol transaction");
|
||||
// require all outputs in a tx be of the same type
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
|
||||
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
|
||||
<< "expected matching variant types in protocol transaction");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// require outputs be of type txout_to_key OR txout_to_tagged_key
|
||||
// to allow grace period before requiring all to be txout_to_tagged_key
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction");
|
||||
|
||||
// require all outputs in a tx be of the same type
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
|
||||
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
|
||||
<< "expected matching variant types in transaction");
|
||||
}
|
||||
|
||||
// Verify the asset type
|
||||
std::string asset_type;
|
||||
CHECK_AND_ASSERT_MES(cryptonote::get_output_asset_type(o, asset_type), false, "failed to get asset type");
|
||||
if (hf_version < HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
// Prior to the first audit, ONLY SAL was supported
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
} else {
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: This will NOT always be the case - when we add an audit for SALx it'll need to support that as well
|
||||
// The CHANGE for an AUDIT TX must be SAL (and 0 value, and unspendable, and to the origin wallet, and ...)
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
// LAND AHOY!!!
|
||||
} else if (tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
if (hf_version < HF_VERSION_AUDIT1_PAUSE) {
|
||||
// PROTOCOL TXs are responsible for paying out SAL and SAL1 during the first AUDIT
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1" || asset_type == "SAL", false, "wrong output asset type:" << asset_type);
|
||||
} else {
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
|
||||
}
|
||||
} else {
|
||||
// All other TX types must only spend + create SAL1 (MINER, TRANSFER)
|
||||
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -135,6 +135,10 @@ namespace cryptonote
|
||||
uint64_t get_outs_money_amount(const transaction& tx);
|
||||
std::string asset_type_from_id(const uint32_t asset_type_id);
|
||||
uint32_t asset_id_from_type(const std::string asset_type);
|
||||
bool is_valid_custom_asset_type(const std::string& asset_type);
|
||||
bool is_valid_asset_type(const std::string& asset_type);
|
||||
bool is_asset_type_token(const std::string& asset_type);
|
||||
uint64_t get_token_creation_price(const std::string& ticker);
|
||||
bool get_tx_asset_types(const transaction& tx, const crypto::hash &txid, std::string& source, std::string& destination, const bool is_miner_tx);
|
||||
bool get_output_public_key(const cryptonote::tx_out& out, crypto::public_key& output_public_key);
|
||||
boost::optional<crypto::view_tag> get_output_view_tag(const cryptonote::tx_out& out);
|
||||
|
||||
@@ -104,7 +104,9 @@ namespace cryptonote
|
||||
}
|
||||
|
||||
|
||||
miner::miner(i_miner_handler* phandler, const get_block_hash_t &gbh):m_stop(1),
|
||||
miner::miner(i_miner_handler* phandler, const get_block_hash_t &gbh):
|
||||
m_forced_stop(1),
|
||||
m_stop(1),
|
||||
m_template{},
|
||||
m_template_no(0),
|
||||
m_diffic(0),
|
||||
@@ -173,9 +175,12 @@ namespace cryptonote
|
||||
|
||||
uint64_t seed_height;
|
||||
crypto::hash seed_hash;
|
||||
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, seed_height, seed_hash))
|
||||
crypto::public_key miner_reward_tx_key;
|
||||
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, seed_height, seed_hash, miner_reward_tx_key))
|
||||
{
|
||||
LOG_ERROR("Failed to get_block_template(), stopping mining");
|
||||
m_forced_stop = true;
|
||||
m_stop = true;
|
||||
return false;
|
||||
}
|
||||
set_block_template(bl, di, height, expected_reward);
|
||||
@@ -185,7 +190,17 @@ namespace cryptonote
|
||||
bool miner::on_idle()
|
||||
{
|
||||
m_update_block_template_interval.do_call([&](){
|
||||
if(is_mining())request_block_template();
|
||||
if(is_mining()) {
|
||||
// Request the block template
|
||||
request_block_template();
|
||||
} else {
|
||||
// Check for forced stop
|
||||
if (m_forced_stop) {
|
||||
if (!m_threads_active) {
|
||||
stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -393,8 +408,12 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
request_block_template();//lets update block template
|
||||
if (!request_block_template()) {
|
||||
LOG_ERROR("Unable to start miner - unknown error");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_forced_stop = false;
|
||||
m_stop = false;
|
||||
m_thread_index = 0;
|
||||
set_is_background_mining_enabled(do_background);
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace cryptonote
|
||||
struct i_miner_handler
|
||||
{
|
||||
virtual bool handle_block_found(block& b, block_verification_context &bvc) = 0;
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash) = 0;
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key) = 0;
|
||||
protected:
|
||||
~i_miner_handler(){};
|
||||
};
|
||||
@@ -118,6 +118,7 @@ namespace cryptonote
|
||||
};
|
||||
|
||||
|
||||
std::atomic<bool> m_forced_stop;
|
||||
std::atomic<bool> m_stop;
|
||||
epee::critical_section m_template_lock;
|
||||
block m_template;
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#define TX_EXTRA_NONCE 0x02
|
||||
#define TX_EXTRA_MERGE_MINING_TAG 0x03
|
||||
#define TX_EXTRA_TAG_ADDITIONAL_PUBKEYS 0x04
|
||||
#define TX_EXTRA_TAG_TOKEN 0x80
|
||||
#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE
|
||||
|
||||
#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
|
||||
@@ -167,6 +168,15 @@ namespace cryptonote
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_token
|
||||
{
|
||||
cryptonote::token_metadata_t token;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
FIELD(token)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct tx_extra_mysterious_minergate
|
||||
{
|
||||
std::string data;
|
||||
@@ -180,7 +190,7 @@ namespace cryptonote
|
||||
// varint tag;
|
||||
// varint size;
|
||||
// varint data[];
|
||||
typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag, tx_extra_additional_pub_keys, tx_extra_mysterious_minergate> tx_extra_field;
|
||||
typedef boost::variant<tx_extra_padding, tx_extra_pub_key, tx_extra_nonce, tx_extra_merge_mining_tag, tx_extra_additional_pub_keys, tx_extra_mysterious_minergate, tx_extra_token> tx_extra_field;
|
||||
}
|
||||
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
|
||||
@@ -189,3 +199,4 @@ VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
|
||||
VARIANT_TAG(binary_archive, cryptonote::tx_extra_token, TX_EXTRA_TAG_TOKEN);
|
||||
|
||||
+85
-63
@@ -44,9 +44,11 @@
|
||||
#define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000
|
||||
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
|
||||
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
|
||||
#define CURRENT_TRANSACTION_VERSION 3
|
||||
#define CURRENT_TRANSACTION_VERSION 5
|
||||
#define TRANSACTION_VERSION_2_OUTS 2
|
||||
#define TRANSACTION_VERSION_N_OUTS 3
|
||||
#define TRANSACTION_VERSION_CARROT 4
|
||||
#define TRANSACTION_VERSION_ENABLE_TOKENS 5
|
||||
#define CURRENT_BLOCK_MAJOR_VERSION 1
|
||||
#define CURRENT_BLOCK_MINOR_VERSION 1
|
||||
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
|
||||
@@ -87,8 +89,14 @@
|
||||
#define PREMINE_AMOUNT_UPFRONT ((uint64_t)650000000000000ull) // 3.4% of MONEY_SUPPLY
|
||||
#define PREMINE_AMOUNT_MONTHLY ((uint64_t)65000000000000ull) // 8.6%/24 of MONEY_SUPPLY
|
||||
|
||||
#define TREASURY_SAL1_MINT_AMOUNT ((uint64_t)65000000000000ull) // 650K
|
||||
#define TREASURY_SAL1_MINT_COUNT 16 // 16 times
|
||||
#define TREASURY_SAL1_MINT_AMOUNT ((uint64_t)130000000000000ull) // 1.3M
|
||||
#define TREASURY_SAL1_MINT_COUNT 8 // 8 times
|
||||
|
||||
#define CREATE_TOKEN_LOCK_PERIOD 10
|
||||
|
||||
// HF11 block reward split
|
||||
#define BLOCK_REWARD_TREASURY_PCT 25 // to treasury, 21600-block unlock
|
||||
#define BLOCK_REWARD_STAKER_PCT 20 // to stakers via yield
|
||||
|
||||
#define DIFFICULTY_TARGET_V2 120 // seconds
|
||||
#define DIFFICULTY_TARGET_V1 60 // seconds - before first fork
|
||||
@@ -243,13 +251,14 @@
|
||||
#define HF_VERSION_AUDIT2 8
|
||||
#define HF_VERSION_AUDIT2_PAUSE 9
|
||||
#define HF_VERSION_CARROT 10
|
||||
#define HF_VERSION_ENABLE_TOKENS 11
|
||||
|
||||
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
|
||||
#define HF_VERSION_ENABLE_CONVERT 255
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
#define HF_VERSION_SLIPPAGE_YIELD 255
|
||||
|
||||
#define TESTNET_VERSION 14
|
||||
#define TESTNET_VERSION 18
|
||||
#define STAGENET_VERSION 1
|
||||
|
||||
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
|
||||
@@ -292,6 +301,9 @@ namespace config
|
||||
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 0x3ef318; // SaLv
|
||||
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0x55ef318; // SaLvi
|
||||
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0xf5ef318; // SaLvs
|
||||
uint64_t const CARROT_PUBLIC_ADDRESS_BASE58_PREFIX = 0x180c96; // SC1
|
||||
uint64_t const CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0x2ccc96; // SC1i
|
||||
uint64_t const CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0x314c96; // SC1s
|
||||
uint16_t const P2P_DEFAULT_PORT = 19080;
|
||||
uint16_t const RPC_DEFAULT_PORT = 19081;
|
||||
uint16_t const ZMQ_RPC_DEFAULT_PORT = 19082;
|
||||
@@ -311,26 +323,19 @@ namespace config
|
||||
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
|
||||
const uint64_t TREASURY_SAL1_MINT_PERIOD = 30*24*30; // 1 month of blocks
|
||||
|
||||
std::string const TREASURY_ADDRESS_CARROT = "SC11ksHLFhy7H1yMk9bUZvADG1Z9ZkR1T5QMknm3RbGBbgdPkyanB2WBb5TER3MsiwJC5BnyoiYs2DBcvAfAm6JQ537iNKdtvm";
|
||||
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
|
||||
|
||||
// treasury payout {tx-key, output-key} pairs
|
||||
const std::vector<std::pair<std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_KEYS = {
|
||||
{"a1bdd1da651fbbb845232816e1aa2d4ff29b790f10bbd4f574a012f1199e15a4", "b0733ab6f251b16458efa9ebb3fb99bd54d43173b5768fe9ffc42e0fe46ae3a8"},
|
||||
{"47996eccbcc078b06d0f6ece37bf3a700c2bd60adfdd898b22096f16a9ad315c", "fd6bcceb4799ee067d59b97a6f66a0f9a70f134220259d3b4d6a2278ba4aca4c"},
|
||||
{"a3e6754a849b80c21a77e6065fefdae29eeeabf17c407453356244a00545bdb8", "3d395454df1452d715d27190e022b20395871c99af578f7251c3f9752e0274a6"},
|
||||
{"0d5e97a910e0f9c606ad9c711b6595aaed142d857cde2efa519112b9a29240d5", "56c29e28bdcf4f20b4b45906b93ae7c4bf9ee82e18cd45543cb69a14ce5efb88"},
|
||||
{"495fa363de88915aa8b74818c4b80715a882a688b4f7127ab7cd3b6885f3567a", "d42dfe0da5579c82e8255eba8c0a17170023f14a6a5030da6abf9f10abb52cbb"},
|
||||
{"85ea10ec40390e4f406446fb519e974d89536154045c6df28bb3b538b254e20d", "0ce2b7dd3a8ce8b596889dac8081a62f98fd70f1f043944ab4ac592c3c59e77b"},
|
||||
{"40f201b38a319dda81e7201e57fea7924067a4a332ed71b8e51ec29ac2d67310", "8289aa6963b98d1034e94eae55d8be6b33d0a88f14f174ebcbaec70837986c7c"},
|
||||
{"c5a648cc7846341357b7b4653a58f9eb4800d88b5de587bceec7a5c28f98d05a", "3f308a203845d88e5e728fcebcdcea1f90e2f424d461617993c672a6138ad2d8"},
|
||||
{"4c51d6550b8eeb6cc8f0d395cc83a5f90ec2a4d86501b3f68da48d618ccf5711", "53f0bd8cebeefb3a88fffa5d7f6ad43d4712608ded561732467ca499df940454"},
|
||||
{"ce2f5d82118fed03d5e269e285fc16189a6cd34f38999e5c055a5dea5fce61bc", "f7fc6948b194d9bd6f2df6ecb83f04e6c8d1a2556a63fedb310a4631fe1bfc42"},
|
||||
{"6248028fd77fb02b5c6ea72dea10b417891a2da7aaf9565aed382e063b4981a3", "63986e1177499bdb23cd49afb519ec18f38cb1b0c386220b376d8ffdc2e37890"},
|
||||
{"6adcb695aa5d6d01133c68900f29e501e9549816e827ea0c164bbc78f3534dd6", "6a440ccb18f5e703e8000de3865ac40d4c18f081270d32eef377dc831f28d8d0"},
|
||||
{"b97a4d2259480f34f20e41c489ab5c2e5ae9ee84d8672a7eff8012f2260e121e", "e6eb9147ff40e22209d321d0f1bfbfe20acf5ceb6b9d0bfb13688ad28aa1232e"},
|
||||
{"4fd214602a36902f22d16927244c456e8cc5a406a9570131f138a028214ffdf0", "34060b8bd96009b9b298280ebd84fa9587fa8c9df6fb5ad0270fb6cd2098885c"},
|
||||
{"9d60178ec6d6599d7a31298f2559fb9c3111f2c70494b3a1638db877ea55b808", "7985ed03856a929663e954738d0938713407717835f760c7ca4d54844a128c91"},
|
||||
{"cd65718eab234bf419332e53bd2f48e2ade70af48c5e126ab5080321e1493dfc", "581cb4cca7a0a029ee2cac51dfc00a0c3a657d2eaf67ed3c6ae7bacc11b4f007"},
|
||||
// treasury payout {tx-key, output-key, anchor_enc, view_tag} tuples
|
||||
const std::map<uint64_t, std::tuple<std::string, std::string, std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_DATA = {
|
||||
{334750, {"1b2cd3ff56aa77c0cbab0473bfb96697ebdd0b25ad230136bfe41d5dc1ef265f","718cf02eabca157fd7ad7f8537db217624bfe1ca99dd09e758357e7000a5e57a","789cca3def51fb879eb7fbca271869b7","79bd0c"}},
|
||||
{356350, {"b51acbf35265d09f3cfb83dcabde2746991ddf0d30b5a4ecc34043b349a77031","9dc0d2e9534cdccf83494687c55c67c8c1b29834acf97cce53124a08a9549231","588ebc2918d06c009a18a28a8ab76694","ab8c23"}},
|
||||
{377950, {"771c6865980493846cbb049b34f72b937878cf799ae1126775df35064cf53526","60d340613c7721aeb03f2de1b56e2916d6cb023cc668acaca00e1606e0bb7f64","198bb0e5880c8abf8108158284ca7637","9b93f2"}},
|
||||
{399550, {"d9159f9bb654230382a69bb7a739c14f9d506c21dba5be9f4cdf66126ed1b24e","c3b34e7f9977f31f659abd9306b650416a674ed7bcfb8c75b257040a1a06b8b9","6f0de181716e0a9e100228d58f11d42c","4c87fd"}},
|
||||
{421150, {"1e2ab1ae204e7a9375f5b57fed2524e2d1a4702c4bbc6d420eb65d92af44c60c","826ecca0e2837860a6d2be89a410ff6aab22c5f5a66bd0a318de3abe646aa26a","bad663aa8253c40d00de0a2d1dfca60f","4a04d7"}},
|
||||
{442750, {"18267940a2b37c82850f3fb83d935281ee5cc436b0797ec10ca26c9cc3c0ef01","77bdec7bbc4cabd84cc8cf0666e1fdfe299480b9b2a4cf52cc959d728fa899ab","a8807121e33471cf18aa82af4826c9a7","d35d35"}},
|
||||
{464350, {"9ab50223bfecec2508e8233540dc13c3fc7e15a8d77ecb90939afee96859724d","675a1b3f2a2cd2bd0e7ec073c426125d95e12ad13e541bf019925c481c2bca15","591d2f2331832c347654ab255ad97e2d","d87c9c"}},
|
||||
{485950, {"c0d7299fe0b873687e7319f1a0d1f67712ef3ccf6a579d96c5f99743add6f029","dd3d17b5145b56377e023c169ae858cdf48bd6c23e8b2a77e02765ce316e3ca7","6a9e74df01762e2b32db1dc4d69dc3e9","75debe"}}
|
||||
};
|
||||
|
||||
// Hash domain separators
|
||||
@@ -396,6 +401,9 @@ namespace config
|
||||
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 0x15beb318; // SaLvT
|
||||
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0xd055eb318; // SaLvTi
|
||||
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0xa59eb318; // SaLvTs
|
||||
uint64_t const CARROT_PUBLIC_ADDRESS_BASE58_PREFIX = 0x254c96; // SC1T
|
||||
uint64_t const CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0x1ac50c96; // SC1Ti
|
||||
uint64_t const CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0x3c54c96; // SC1Ts
|
||||
uint16_t const P2P_DEFAULT_PORT = 29080;
|
||||
uint16_t const RPC_DEFAULT_PORT = 29081;
|
||||
uint16_t const ZMQ_RPC_DEFAULT_PORT = 29082;
|
||||
@@ -420,26 +428,20 @@ namespace config
|
||||
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
|
||||
std::string const TREASURY_ADDRESS = "SaLvTyLFta9BiAXeUfFkKvViBkFt4ay5nEUBpWyDKewYggtsoxBbtCUVqaBjtcCDyY1euun8Giv7LLEgvztuurLo5a6Km1zskZn36";
|
||||
std::string const TREASURY_ADDRESS_CARROT = "SC1TouvX6e4HmkAqsU6AAXLRjgeZnnKHjSpVfMHepTXramNMT2P47AsDmteLH81wdPR2DwMg3cxKvgrhUBeDSUW6MhM3sQb92we";
|
||||
std::string const TREASURY_ADDRESS = "SaLvTyL2pN2SCAPRxwDQ7qjhdg46VbhZrGZTp2wHKJ5sK434a8ivEH35eWp2FTcmyW6LY6ExfBb9chmQ9xAL1eJyZ5FQjtQGTis3v";
|
||||
|
||||
// treasury payout {tx-key, output-key} pairs
|
||||
const std::vector<std::pair<std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_KEYS = {
|
||||
{"a1bdd1da651fbbb845232816e1aa2d4ff29b790f10bbd4f574a012f1199e15a4", "b0733ab6f251b16458efa9ebb3fb99bd54d43173b5768fe9ffc42e0fe46ae3a8"},
|
||||
{"47996eccbcc078b06d0f6ece37bf3a700c2bd60adfdd898b22096f16a9ad315c", "fd6bcceb4799ee067d59b97a6f66a0f9a70f134220259d3b4d6a2278ba4aca4c"},
|
||||
{"a3e6754a849b80c21a77e6065fefdae29eeeabf17c407453356244a00545bdb8", "3d395454df1452d715d27190e022b20395871c99af578f7251c3f9752e0274a6"},
|
||||
{"0d5e97a910e0f9c606ad9c711b6595aaed142d857cde2efa519112b9a29240d5", "56c29e28bdcf4f20b4b45906b93ae7c4bf9ee82e18cd45543cb69a14ce5efb88"},
|
||||
{"495fa363de88915aa8b74818c4b80715a882a688b4f7127ab7cd3b6885f3567a", "d42dfe0da5579c82e8255eba8c0a17170023f14a6a5030da6abf9f10abb52cbb"},
|
||||
{"85ea10ec40390e4f406446fb519e974d89536154045c6df28bb3b538b254e20d", "0ce2b7dd3a8ce8b596889dac8081a62f98fd70f1f043944ab4ac592c3c59e77b"},
|
||||
{"40f201b38a319dda81e7201e57fea7924067a4a332ed71b8e51ec29ac2d67310", "8289aa6963b98d1034e94eae55d8be6b33d0a88f14f174ebcbaec70837986c7c"},
|
||||
{"c5a648cc7846341357b7b4653a58f9eb4800d88b5de587bceec7a5c28f98d05a", "3f308a203845d88e5e728fcebcdcea1f90e2f424d461617993c672a6138ad2d8"},
|
||||
{"4c51d6550b8eeb6cc8f0d395cc83a5f90ec2a4d86501b3f68da48d618ccf5711", "53f0bd8cebeefb3a88fffa5d7f6ad43d4712608ded561732467ca499df940454"},
|
||||
{"ce2f5d82118fed03d5e269e285fc16189a6cd34f38999e5c055a5dea5fce61bc", "f7fc6948b194d9bd6f2df6ecb83f04e6c8d1a2556a63fedb310a4631fe1bfc42"},
|
||||
{"6248028fd77fb02b5c6ea72dea10b417891a2da7aaf9565aed382e063b4981a3", "63986e1177499bdb23cd49afb519ec18f38cb1b0c386220b376d8ffdc2e37890"},
|
||||
{"6adcb695aa5d6d01133c68900f29e501e9549816e827ea0c164bbc78f3534dd6", "6a440ccb18f5e703e8000de3865ac40d4c18f081270d32eef377dc831f28d8d0"},
|
||||
{"b97a4d2259480f34f20e41c489ab5c2e5ae9ee84d8672a7eff8012f2260e121e", "e6eb9147ff40e22209d321d0f1bfbfe20acf5ceb6b9d0bfb13688ad28aa1232e"},
|
||||
{"4fd214602a36902f22d16927244c456e8cc5a406a9570131f138a028214ffdf0", "34060b8bd96009b9b298280ebd84fa9587fa8c9df6fb5ad0270fb6cd2098885c"},
|
||||
{"9d60178ec6d6599d7a31298f2559fb9c3111f2c70494b3a1638db877ea55b808", "7985ed03856a929663e954738d0938713407717835f760c7ca4d54844a128c91"},
|
||||
{"cd65718eab234bf419332e53bd2f48e2ade70af48c5e126ab5080321e1493dfc", "581cb4cca7a0a029ee2cac51dfc00a0c3a657d2eaf67ed3c6ae7bacc11b4f007"},
|
||||
// treasury payout {tx-key, output-key, anchor_enc, vie_tag} tuples
|
||||
// check address type before future development
|
||||
const std::map<uint64_t, std::tuple<std::string, std::string, std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_DATA = {
|
||||
{1100, {"71336a480440ed24a53b2cfd5a5292d1e618c3e843637227883ea2cc42fb346f","a135f59a05ea9e33539e4502b187b4789cc7fba79616c6902a902cc6601f0359","7f1c6970232254a9b13f7f063df2a853","62073c"}},
|
||||
{1120, {"2cc49b182addc0106b601c9876c01a4b06532c05f9dd9179b2c4f47e5c7c0d74","fd62e59324389f37d0bb628a39f413c11be34d572ec3a40f465e008b9dfd5e0c","fbf8584222e299bb748009eaf2177123","b76a8d"}},
|
||||
{1140, {"50f1dd5244bb6fdc62b5a18b868a4dc9e9ad15f4a7a54e5a98084a3a5213c846","942de90a3347df3e962d9b0a2745f8aedb265a8caf73aabef9aa713f4ec3e493","933702e29d680bf21ad559a2d3243621","dae32b"}},
|
||||
{1160, {"114a1fef3a03c81b3b6308fb4e51db42d86945d8f71ee8798749a4aa2d8bfe57","fd77f0289b7e25ae68c86f4cd2c72ac0211a4d0e7a31c84b8d58a33bbd3c511b","d8048bb76b9313768a4c69100cba6d43","46b0a3"}},
|
||||
{1180, {"cf7fe9d97a7a4cb881bff1d37bb6981bcb0691649c465d660522a43f14b32849","b76908d56108e7111374f60993e9411def7bb2899118f20f49e67a801936a1ad","f203a5acd48f93f1451d32d70716e585","d72097"}},
|
||||
{1200, {"415e8fa4fb6bed8bc59591883f5e098dde6179e980eccfc4cbb3a64c4168cf47","5426c588d7c5750c76b526ef268b45f7414e2ddea40218ee92d123564c5114c4","fb1926bbef8c70ebd796ae77dffca07d","351edf"}},
|
||||
{1220, {"1f47cce00e8e1c77cb3ff007491d261dae75de5bbfdbe0f4913d74a8503aaa5e","4d8aac299306989aa169982d89457852a1bab858c668c9b740d96b682bb1961b","d8c0be7926ce704290cfd8d5e0500f33","750003"}},
|
||||
{1240, {"3afd93c684638d54e68f5d8d417863035f12482251feea5cf7515725a2bb0f4f","7895e6baded473b093b57993ae3497a47b0ea78cf35b37d1387f226f445d9018","76a0c37e6f3d9d508c4bce1d7162514e","09e146"}}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -448,6 +450,9 @@ namespace config
|
||||
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 0x149eb318; // SaLvS
|
||||
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0xf343eb318; // SaLvSi
|
||||
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0x2d47eb318; // SaLvSs
|
||||
uint64_t const CARROT_PUBLIC_ADDRESS_BASE58_PREFIX = 0x24cc96; // SC1S
|
||||
uint64_t const CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0x1a848c96; // SC1Si
|
||||
uint64_t const CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0x384cc96; // SC1Ss
|
||||
uint16_t const P2P_DEFAULT_PORT = 39080;
|
||||
uint16_t const RPC_DEFAULT_PORT = 39081;
|
||||
uint16_t const ZMQ_RPC_DEFAULT_PORT = 39082;
|
||||
@@ -469,26 +474,27 @@ namespace config
|
||||
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
|
||||
"-----END PUBLIC KEY-----\n";
|
||||
|
||||
std::string const TREASURY_ADDRESS_CARROT = ""; // TODO: generate stagenet Carrot treasury address ?
|
||||
std::string const TREASURY_ADDRESS = "fuLMowH85abK8nz9BBMEem7MAfUbQu4aSHHUV9j5Z86o6Go9Lv2U5ZQiJCWPY9R9HA8p5idburazjAhCqDngLo7fYPCD9ciM9ee1A";
|
||||
|
||||
// treasury payout {tx-key, output-key} pairs
|
||||
const std::vector<std::pair<std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_KEYS = {
|
||||
{"a1bdd1da651fbbb845232816e1aa2d4ff29b790f10bbd4f574a012f1199e15a4", "b0733ab6f251b16458efa9ebb3fb99bd54d43173b5768fe9ffc42e0fe46ae3a8"},
|
||||
{"47996eccbcc078b06d0f6ece37bf3a700c2bd60adfdd898b22096f16a9ad315c", "fd6bcceb4799ee067d59b97a6f66a0f9a70f134220259d3b4d6a2278ba4aca4c"},
|
||||
{"a3e6754a849b80c21a77e6065fefdae29eeeabf17c407453356244a00545bdb8", "3d395454df1452d715d27190e022b20395871c99af578f7251c3f9752e0274a6"},
|
||||
{"0d5e97a910e0f9c606ad9c711b6595aaed142d857cde2efa519112b9a29240d5", "56c29e28bdcf4f20b4b45906b93ae7c4bf9ee82e18cd45543cb69a14ce5efb88"},
|
||||
{"495fa363de88915aa8b74818c4b80715a882a688b4f7127ab7cd3b6885f3567a", "d42dfe0da5579c82e8255eba8c0a17170023f14a6a5030da6abf9f10abb52cbb"},
|
||||
{"85ea10ec40390e4f406446fb519e974d89536154045c6df28bb3b538b254e20d", "0ce2b7dd3a8ce8b596889dac8081a62f98fd70f1f043944ab4ac592c3c59e77b"},
|
||||
{"40f201b38a319dda81e7201e57fea7924067a4a332ed71b8e51ec29ac2d67310", "8289aa6963b98d1034e94eae55d8be6b33d0a88f14f174ebcbaec70837986c7c"},
|
||||
{"c5a648cc7846341357b7b4653a58f9eb4800d88b5de587bceec7a5c28f98d05a", "3f308a203845d88e5e728fcebcdcea1f90e2f424d461617993c672a6138ad2d8"},
|
||||
{"4c51d6550b8eeb6cc8f0d395cc83a5f90ec2a4d86501b3f68da48d618ccf5711", "53f0bd8cebeefb3a88fffa5d7f6ad43d4712608ded561732467ca499df940454"},
|
||||
{"ce2f5d82118fed03d5e269e285fc16189a6cd34f38999e5c055a5dea5fce61bc", "f7fc6948b194d9bd6f2df6ecb83f04e6c8d1a2556a63fedb310a4631fe1bfc42"},
|
||||
{"6248028fd77fb02b5c6ea72dea10b417891a2da7aaf9565aed382e063b4981a3", "63986e1177499bdb23cd49afb519ec18f38cb1b0c386220b376d8ffdc2e37890"},
|
||||
{"6adcb695aa5d6d01133c68900f29e501e9549816e827ea0c164bbc78f3534dd6", "6a440ccb18f5e703e8000de3865ac40d4c18f081270d32eef377dc831f28d8d0"},
|
||||
{"b97a4d2259480f34f20e41c489ab5c2e5ae9ee84d8672a7eff8012f2260e121e", "e6eb9147ff40e22209d321d0f1bfbfe20acf5ceb6b9d0bfb13688ad28aa1232e"},
|
||||
{"4fd214602a36902f22d16927244c456e8cc5a406a9570131f138a028214ffdf0", "34060b8bd96009b9b298280ebd84fa9587fa8c9df6fb5ad0270fb6cd2098885c"},
|
||||
{"9d60178ec6d6599d7a31298f2559fb9c3111f2c70494b3a1638db877ea55b808", "7985ed03856a929663e954738d0938713407717835f760c7ca4d54844a128c91"},
|
||||
{"cd65718eab234bf419332e53bd2f48e2ade70af48c5e126ab5080321e1493dfc", "581cb4cca7a0a029ee2cac51dfc00a0c3a657d2eaf67ed3c6ae7bacc11b4f007"},
|
||||
// treasury payout {tx-key, output-key, anchor_enc, view_tag} tuples
|
||||
const std::map<uint64_t, std::tuple<std::string, std::string, std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_DATA = {
|
||||
{1000000ULL, {"a1bdd1da651fbbb845232816e1aa2d4ff29b790f10bbd4f574a012f1199e15a4", "b0733ab6f251b16458efa9ebb3fb99bd54d43173b5768fe9ffc42e0fe46ae3a8", "00", "00"}},
|
||||
{1020000ULL, {"47996eccbcc078b06d0f6ece37bf3a700c2bd60adfdd898b22096f16a9ad315c", "fd6bcceb4799ee067d59b97a6f66a0f9a70f134220259d3b4d6a2278ba4aca4c", "00", "00"}},
|
||||
{1040000ULL, {"a3e6754a849b80c21a77e6065fefdae29eeeabf17c407453356244a00545bdb8", "3d395454df1452d715d27190e022b20395871c99af578f7251c3f9752e0274a6", "00", "00"}},
|
||||
{1060000ULL, {"0d5e97a910e0f9c606ad9c711b6595aaed142d857cde2efa519112b9a29240d5", "56c29e28bdcf4f20b4b45906b93ae7c4bf9ee82e18cd45543cb69a14ce5efb88", "00", "00"}},
|
||||
{1080000ULL, {"495fa363de88915aa8b74818c4b80715a882a688b4f7127ab7cd3b6885f3567a", "d42dfe0da5579c82e8255eba8c0a17170023f14a6a5030da6abf9f10abb52cbb", "00", "00"}},
|
||||
{1100000ULL, {"85ea10ec40390e4f406446fb519e974d89536154045c6df28bb3b538b254e20d", "0ce2b7dd3a8ce8b596889dac8081a62f98fd70f1f043944ab4ac592c3c59e77b", "00", "00"}},
|
||||
{1120000ULL, {"40f201b38a319dda81e7201e57fea7924067a4a332ed71b8e51ec29ac2d67310", "8289aa6963b98d1034e94eae55d8be6b33d0a88f14f174ebcbaec70837986c7c", "00", "00"}},
|
||||
{1140000ULL, {"c5a648cc7846341357b7b4653a58f9eb4800d88b5de587bceec7a5c28f98d05a", "3f308a203845d88e5e728fcebcdcea1f90e2f424d461617993c672a6138ad2d8", "00", "00"}},
|
||||
{1160000ULL, {"4c51d6550b8eeb6cc8f0d395cc83a5f90ec2a4d86501b3f68da48d618ccf5711", "53f0bd8cebeefb3a88fffa5d7f6ad43d4712608ded561732467ca499df940454", "00", "00"}},
|
||||
{1180000ULL, {"ce2f5d82118fed03d5e269e285fc16189a6cd34f38999e5c055a5dea5fce61bc", "f7fc6948b194d9bd6f2df6ecb83f04e6c8d1a2556a63fedb310a4631fe1bfc42", "00", "00"}},
|
||||
{1200000ULL, {"6248028fd77fb02b5c6ea72dea10b417891a2da7aaf9565aed382e063b4981a3", "63986e1177499bdb23cd49afb519ec18f38cb1b0c386220b376d8ffdc2e37890", "00", "00"}},
|
||||
{1220000ULL, {"6adcb695aa5d6d01133c68900f29e501e9549816e827ea0c164bbc78f3534dd6", "6a440ccb18f5e703e8000de3865ac40d4c18f081270d32eef377dc831f28d8d0", "00", "00"}},
|
||||
{1240000ULL, {"b97a4d2259480f34f20e41c489ab5c2e5ae9ee84d8672a7eff8012f2260e121e", "e6eb9147ff40e22209d321d0f1bfbfe20acf5ceb6b9d0bfb13688ad28aa1232e", "00", "00"}},
|
||||
{1260000ULL, {"4fd214602a36902f22d16927244c456e8cc5a406a9570131f138a028214ffdf0", "34060b8bd96009b9b298280ebd84fa9587fa8c9df6fb5ad0270fb6cd2098885c", "00", "00"}},
|
||||
{1280000ULL, {"9d60178ec6d6599d7a31298f2559fb9c3111f2c70494b3a1638db877ea55b808", "7985ed03856a929663e954738d0938713407717835f760c7ca4d54844a128c91", "00", "00"}},
|
||||
{1300000ULL, {"cd65718eab234bf419332e53bd2f48e2ade70af48c5e126ab5080321e1493dfc", "581cb4cca7a0a029ee2cac51dfc00a0c3a657d2eaf67ed3c6ae7bacc11b4f007", "00", "00"}},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -508,6 +514,9 @@ namespace cryptonote
|
||||
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX;
|
||||
uint64_t const CARROT_PUBLIC_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t const CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t const CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX;
|
||||
uint16_t const P2P_DEFAULT_PORT;
|
||||
uint16_t const RPC_DEFAULT_PORT;
|
||||
uint16_t const ZMQ_RPC_DEFAULT_PORT;
|
||||
@@ -520,7 +529,8 @@ namespace cryptonote
|
||||
uint64_t TREASURY_SAL1_MINT_PERIOD;
|
||||
std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> const AUDIT_HARD_FORKS;
|
||||
std::string TREASURY_ADDRESS;
|
||||
std::vector<std::pair<std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_KEYS;
|
||||
std::string TREASURY_ADDRESS_CARROT;
|
||||
std::map<uint64_t, std::tuple<std::string, std::string, std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_DATA;
|
||||
};
|
||||
inline const config_t& get_config(network_type nettype)
|
||||
{
|
||||
@@ -528,6 +538,9 @@ namespace cryptonote
|
||||
::config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX,
|
||||
::config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX,
|
||||
::config::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX,
|
||||
::config::CARROT_PUBLIC_ADDRESS_BASE58_PREFIX,
|
||||
::config::CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX,
|
||||
::config::CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX,
|
||||
::config::P2P_DEFAULT_PORT,
|
||||
::config::RPC_DEFAULT_PORT,
|
||||
::config::ZMQ_RPC_DEFAULT_PORT,
|
||||
@@ -540,12 +553,16 @@ namespace cryptonote
|
||||
::config::TREASURY_SAL1_MINT_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::TREASURY_ADDRESS,
|
||||
::config::TREASURY_SAL1_MINT_OUTPUT_KEYS
|
||||
::config::TREASURY_ADDRESS_CARROT,
|
||||
::config::TREASURY_SAL1_MINT_OUTPUT_DATA
|
||||
};
|
||||
static const config_t testnet = {
|
||||
::config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX,
|
||||
::config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX,
|
||||
::config::testnet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX,
|
||||
::config::testnet::CARROT_PUBLIC_ADDRESS_BASE58_PREFIX,
|
||||
::config::testnet::CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX,
|
||||
::config::testnet::CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX,
|
||||
::config::testnet::P2P_DEFAULT_PORT,
|
||||
::config::testnet::RPC_DEFAULT_PORT,
|
||||
::config::testnet::ZMQ_RPC_DEFAULT_PORT,
|
||||
@@ -558,12 +575,16 @@ namespace cryptonote
|
||||
::config::testnet::TREASURY_SAL1_MINT_PERIOD,
|
||||
::config::testnet::AUDIT_HARD_FORKS,
|
||||
::config::testnet::TREASURY_ADDRESS,
|
||||
::config::testnet::TREASURY_SAL1_MINT_OUTPUT_KEYS
|
||||
::config::testnet::TREASURY_ADDRESS_CARROT,
|
||||
::config::testnet::TREASURY_SAL1_MINT_OUTPUT_DATA
|
||||
};
|
||||
static const config_t stagenet = {
|
||||
::config::stagenet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX,
|
||||
::config::stagenet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX,
|
||||
::config::stagenet::CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX,
|
||||
::config::stagenet::CARROT_PUBLIC_ADDRESS_BASE58_PREFIX,
|
||||
::config::stagenet::CARROT_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX,
|
||||
::config::stagenet::CARROT_PUBLIC_SUBADDRESS_BASE58_PREFIX,
|
||||
::config::stagenet::P2P_DEFAULT_PORT,
|
||||
::config::stagenet::RPC_DEFAULT_PORT,
|
||||
::config::stagenet::ZMQ_RPC_DEFAULT_PORT,
|
||||
@@ -576,7 +597,8 @@ namespace cryptonote
|
||||
::config::stagenet::TREASURY_SAL1_MINT_PERIOD,
|
||||
::config::stagenet::AUDIT_HARD_FORKS,
|
||||
::config::stagenet::TREASURY_ADDRESS,
|
||||
::config::stagenet::TREASURY_SAL1_MINT_OUTPUT_KEYS
|
||||
::config::stagenet::TREASURY_ADDRESS_CARROT,
|
||||
::config::stagenet::TREASURY_SAL1_MINT_OUTPUT_DATA
|
||||
};
|
||||
switch (nettype)
|
||||
{
|
||||
|
||||
+797
-143
File diff suppressed because it is too large
Load Diff
@@ -394,8 +394,8 @@ namespace cryptonote
|
||||
*
|
||||
* @return true if block template filled in successfully, else false
|
||||
*/
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
|
||||
bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
|
||||
bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key);
|
||||
bool create_block_template(block& b, const crypto::hash *from_block, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key);
|
||||
|
||||
/**
|
||||
* @brief gets data required to create a block template and start mining on it
|
||||
@@ -726,6 +726,19 @@ namespace cryptonote
|
||||
*/
|
||||
bool check_tx_outputs(const transaction& tx, tx_verification_context &tvc) const;
|
||||
|
||||
/**
|
||||
* @brief check a transaction's input/output/TX asset types conform to current standards
|
||||
*
|
||||
* This function checks, for example at the time of this writing, that
|
||||
* the asset types are supported by the given TX for the current HF version on-chain.
|
||||
*
|
||||
* @param tx the transaction to check the asset types of
|
||||
* @param tvc returned info about tx verification
|
||||
*
|
||||
* @return false if the TX version and/or type is unsupported, otherwise true
|
||||
*/
|
||||
bool check_tx_asset_types(const transaction& tx, tx_verification_context &tvc) const;
|
||||
|
||||
/**
|
||||
* @brief check that a transaction's version & type conforms to current standards
|
||||
*
|
||||
@@ -1175,6 +1188,13 @@ namespace cryptonote
|
||||
*/
|
||||
bool calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_payouts);
|
||||
|
||||
/**
|
||||
* calculate the yield payouts
|
||||
*
|
||||
* @return TRUE if the payouts were calculated successfully, FALSE otherwise
|
||||
*/
|
||||
bool calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info_carrot, uint64_t>>& yield_payouts);
|
||||
|
||||
/**
|
||||
* @brief get the ABI entry for a particular height from the cache
|
||||
*
|
||||
@@ -1226,6 +1246,8 @@ namespace cryptonote
|
||||
*/
|
||||
bool validate_ybi_cache();
|
||||
|
||||
bool is_tx_paid_for(const cryptonote::transaction& tx);
|
||||
|
||||
#ifndef IN_UNIT_TESTS
|
||||
private:
|
||||
#endif
|
||||
@@ -1311,7 +1333,7 @@ namespace cryptonote
|
||||
crypto::hash m_btc_seed_hash;
|
||||
uint64_t m_btc_seed_height;
|
||||
bool m_btc_valid;
|
||||
|
||||
crypto::public_key m_btc_miner_reward_tx_key;
|
||||
|
||||
bool m_batch_success;
|
||||
|
||||
@@ -1500,7 +1522,7 @@ namespace cryptonote
|
||||
*
|
||||
* @return bool indicating payout valid, and the index of the output within miner transaction outputs.
|
||||
*/
|
||||
std::tuple<bool, size_t> validate_treasury_payout(const transaction& tx, const uint64_t payout_index, uint8_t hf_version) const;
|
||||
std::tuple<bool, size_t> validate_treasury_payout(const transaction& tx, const std::tuple<std::string, std::string, std::string, std::string>& treasury_data, uint8_t hf_version) const;
|
||||
|
||||
/**
|
||||
* @brief sanity checks a miner transaction before validating an entire block
|
||||
@@ -1557,10 +1579,11 @@ namespace cryptonote
|
||||
* @param b the block containing the miner transaction to be validated
|
||||
* @param height the blockchain's weight
|
||||
* @param version hard fork version for that transaction
|
||||
* @param txs create_coin transactions in the block
|
||||
*
|
||||
* @return false if anything is found wrong with the protocol transaction, otherwise true
|
||||
*/
|
||||
bool validate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version);
|
||||
bool validate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version, const std::vector<std::pair<transaction, blobdata>>& txs = std::vector<std::pair<transaction, blobdata>>());
|
||||
|
||||
/**
|
||||
* @brief reverts the blockchain to its previous state following a failed switch
|
||||
@@ -1736,7 +1759,7 @@ namespace cryptonote
|
||||
*
|
||||
* At some point, may be used to push an update to miners
|
||||
*/
|
||||
void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie);
|
||||
void cache_block_template(const block &b, const cryptonote::account_public_address &address, const blobdata &nonce, const difficulty_type &diff, uint64_t height, uint64_t expected_reward, uint64_t seed_height, const crypto::hash &seed_hash, uint64_t pool_cookie, crypto::public_key &miner_reward_tx_key);
|
||||
|
||||
/**
|
||||
* @brief sends new block notifications to ZMQ `miner_data` subscribers
|
||||
|
||||
@@ -843,7 +843,10 @@ namespace cryptonote
|
||||
bad_semantics_txes_lock.unlock();
|
||||
|
||||
uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
const size_t max_tx_version = (hf_version >= HF_VERSION_ENABLE_N_OUTS) ? TRANSACTION_VERSION_N_OUTS : TRANSACTION_VERSION_2_OUTS;
|
||||
const size_t max_tx_version = hf_version >= HF_VERSION_ENABLE_TOKENS ? TRANSACTION_VERSION_ENABLE_TOKENS :
|
||||
hf_version >= HF_VERSION_CARROT ? TRANSACTION_VERSION_CARROT :
|
||||
hf_version >= HF_VERSION_ENABLE_N_OUTS ? TRANSACTION_VERSION_N_OUTS :
|
||||
TRANSACTION_VERSION_2_OUTS;
|
||||
if (tx.version == 0 || tx.version > max_tx_version)
|
||||
{
|
||||
// v2 is the latest one we know
|
||||
@@ -902,6 +905,7 @@ namespace cryptonote
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_incoming_tx_accumulated_batch(std::vector<tx_verification_batch_info> &tx_info, bool keeped_by_block)
|
||||
{
|
||||
const uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
bool ret = true;
|
||||
if (keeped_by_block && get_blockchain_storage().is_within_compiled_block_hash_area())
|
||||
{
|
||||
@@ -923,8 +927,7 @@ namespace cryptonote
|
||||
if (tx_info[n].tx->version < 2)
|
||||
continue;
|
||||
const rct::rctSig &rv = tx_info[n].tx->rct_signatures;
|
||||
const uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) {
|
||||
MERROR_VER("Invalid RCT type provided");
|
||||
set_semantics_failed(tx_info[n].tx_hash);
|
||||
@@ -932,6 +935,14 @@ namespace cryptonote
|
||||
tx_info[n].result = false;
|
||||
return false;
|
||||
}
|
||||
} else if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumZero) {
|
||||
MERROR_VER("Invalid RCT type provided");
|
||||
set_semantics_failed(tx_info[n].tx_hash);
|
||||
tx_info[n].tvc.m_verifivation_failed = true;
|
||||
tx_info[n].result = false;
|
||||
return false;
|
||||
}
|
||||
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs) {
|
||||
MERROR_VER("Invalid RCT type provided");
|
||||
@@ -940,7 +951,11 @@ namespace cryptonote
|
||||
tx_info[n].result = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool need_rollup = false;
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
need_rollup = (tx_info[n].tx->source_asset_type != "SAL1");
|
||||
}
|
||||
switch (rv.type) {
|
||||
case rct::RCTTypeNull:
|
||||
// coinbase should not come here, so we reject for all other types
|
||||
@@ -955,7 +970,8 @@ namespace cryptonote
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
|
||||
0
|
||||
0,
|
||||
need_rollup
|
||||
))
|
||||
{
|
||||
MERROR_VER("rct signature semantics check failed");
|
||||
@@ -990,6 +1006,7 @@ namespace cryptonote
|
||||
break;
|
||||
case rct::RCTTypeBulletproofPlus:
|
||||
case rct::RCTTypeFullProofs:
|
||||
case rct::RCTTypeSalviumZero:
|
||||
case rct::RCTTypeSalviumOne:
|
||||
if (!is_canonical_bulletproof_plus_layout(rv.p.bulletproofs_plus))
|
||||
{
|
||||
@@ -1011,20 +1028,27 @@ namespace cryptonote
|
||||
}
|
||||
if (!rvv.empty())
|
||||
{
|
||||
LOG_PRINT_L1("One transaction among this group has bad semantics, verifying one at a time");
|
||||
LOG_PRINT_L1("Verifying transactions one at a time");
|
||||
ret = false;
|
||||
for (size_t n = 0; n < tx_info.size(); ++n)
|
||||
{
|
||||
if (!tx_info[n].result)
|
||||
continue;
|
||||
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs && tx_info[n].tx->rct_signatures.type != rct::RCTTypeSalviumOne)
|
||||
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs && tx_info[n].tx->rct_signatures.type != rct::RCTTypeSalviumZero && tx_info[n].tx->rct_signatures.type != rct::RCTTypeSalviumOne)
|
||||
continue;
|
||||
bool need_rollup = false;
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
need_rollup = (tx_info[n].tx->source_asset_type != "SAL1");
|
||||
}
|
||||
if (!rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures,
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
|
||||
0
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::CREATE_TOKEN ? tx_info[n].tx->amount_burnt :
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::ROLLUP ? tx_info[n].tx->amount_burnt :
|
||||
0,
|
||||
need_rollup
|
||||
))
|
||||
{
|
||||
set_semantics_failed(tx_info[n].tx_hash);
|
||||
@@ -1238,6 +1262,13 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (hf_version >= HF_VERSION_ENABLE_TOKENS && !m_blockchain_storage.is_tx_paid_for(tx))
|
||||
{
|
||||
MERROR_VER("tx has not been paid for by ROLLUP");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
@@ -1511,14 +1542,14 @@ namespace cryptonote
|
||||
notify_txpool_event(tx_blobs, epee::to_span(tx_hashes), epee::to_span(txs), just_broadcasted);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
|
||||
bool core::get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
|
||||
return m_blockchain_storage.create_block_template(b, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash, miner_reward_tx_key);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash)
|
||||
bool core::get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key)
|
||||
{
|
||||
return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash);
|
||||
return m_blockchain_storage.create_block_template(b, prev_block, adr, diffic, height, expected_reward, ex_nonce, seed_height, seed_hash, miner_reward_tx_key);
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::get_miner_data(uint8_t& major_version, uint64_t& height, crypto::hash& prev_id, crypto::hash& seed_hash, difficulty_type& difficulty, uint64_t& median_weight, uint64_t& already_generated_coins, std::vector<tx_block_template_backlog_entry>& tx_backlog)
|
||||
|
||||
@@ -231,8 +231,8 @@ namespace cryptonote
|
||||
*
|
||||
* @note see Blockchain::create_block_template
|
||||
*/
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash) override;
|
||||
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash);
|
||||
virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key) override;
|
||||
virtual bool get_block_template(block& b, const crypto::hash *prev_block, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, uint64_t& expected_reward, const blobdata& ex_nonce, uint64_t &seed_height, crypto::hash &seed_hash, crypto::public_key &miner_reward_tx_key);
|
||||
|
||||
/**
|
||||
* @copydoc Blockchain::get_miner_data
|
||||
|
||||
@@ -337,34 +337,6 @@ namespace cryptonote
|
||||
}
|
||||
*/
|
||||
//---------------------------------------------------------------
|
||||
std::tuple<bool, uint64_t> check_treasury_payout(
|
||||
network_type nettype,
|
||||
uint64_t height,
|
||||
const std::vector<hardfork_t>& hardforks,
|
||||
const uint8_t hf_version
|
||||
) {
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
// find the hardfork height
|
||||
const auto& hf = std::find_if(hardforks.begin(), hardforks.end(), [](const hardfork_t& hf) {
|
||||
return hf.version == HF_VERSION_CARROT;
|
||||
});
|
||||
|
||||
// since we are at least at the hard fork HF_VERSION_CARROT, we assume height >= hf->height
|
||||
const auto diff = height - hf->height;
|
||||
const auto mint_period = get_config(nettype).TREASURY_SAL1_MINT_PERIOD;
|
||||
|
||||
// pay per period
|
||||
if (diff % mint_period == 0) {
|
||||
const auto payout_index = diff / mint_period;
|
||||
if (payout_index < TREASURY_SAL1_MINT_COUNT) {
|
||||
return {true, payout_index};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {false, 0};
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_protocol_tx(
|
||||
const size_t height,
|
||||
transaction& tx,
|
||||
@@ -374,14 +346,30 @@ namespace cryptonote
|
||||
|
||||
// Clear the TX contents
|
||||
tx.set_null();
|
||||
tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? 3 : 2;
|
||||
bool carrot_found = false;
|
||||
bool noncarrot_found = false;
|
||||
tx.type = cryptonote::transaction_type::PROTOCOL;
|
||||
|
||||
// Force the TX type to 2
|
||||
tx.version = 2;
|
||||
// Scan the protocol_data to make sure all or none are Carrot
|
||||
for (auto const& entry: protocol_data) {
|
||||
if (entry.is_carrot) carrot_found = true;
|
||||
else noncarrot_found = true;
|
||||
}
|
||||
|
||||
const bool do_carrot = hard_fork_version >= HF_VERSION_CARROT;
|
||||
if (do_carrot)
|
||||
if (carrot_found && noncarrot_found) {
|
||||
LOG_ERROR("Cannot mix Carrot and non-Carrot outputs in the same protocol transaction");
|
||||
return false;
|
||||
}
|
||||
if (carrot_found && hard_fork_version < HF_VERSION_CARROT) {
|
||||
LOG_ERROR("Carrot outputs found in CryptoNote protocol transaction");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (carrot_found || (!noncarrot_found && hard_fork_version >= HF_VERSION_CARROT))
|
||||
{
|
||||
// Ensure the TX version is correct
|
||||
tx.version = TRANSACTION_VERSION_CARROT;
|
||||
try
|
||||
{
|
||||
// Create a vector of enotes
|
||||
@@ -390,34 +378,21 @@ namespace cryptonote
|
||||
|
||||
// Iterate over the protocol_data we received, creating an enote for each entry
|
||||
for (auto const& entry: protocol_data) {
|
||||
|
||||
carrot::CarrotDestinationV1 destination;
|
||||
carrot::make_carrot_main_address_v1(entry.P_change,
|
||||
entry.return_address,
|
||||
destination);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(!destination.is_subaddress,
|
||||
"construct_protocol_tx: subaddress are not allowed in miner transactions");
|
||||
CHECK_AND_ASSERT_THROW_MES(destination.payment_id == carrot::null_payment_id,
|
||||
"construct_protocol_tx: integrated addresses are not allowed in miner transactions");
|
||||
|
||||
LOG_PRINT_L2(((entry.type == cryptonote::transaction_type::STAKE) ? "Yield TX payout submitted " : "Audit TX payout submitted ") << entry.amount_burnt << entry.source_asset);
|
||||
|
||||
const carrot::CarrotPaymentProposalV1 payment_proposal{
|
||||
.destination = destination,
|
||||
.amount = entry.amount_burnt,
|
||||
.asset_type = "SAL1",
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
};
|
||||
|
||||
// Build the proposal
|
||||
carrot::CarrotCoinbaseEnoteV1 e;
|
||||
get_coinbase_output_proposal_v1(payment_proposal, height, e);
|
||||
e.onetime_address = entry.return_address;
|
||||
// amount_minted for CREATE_TOKEN, amount_burnt for STAKE/AUDIT
|
||||
e.amount = (entry.type == cryptonote::transaction_type::CREATE_TOKEN) ? entry.amount_minted : entry.amount_burnt;
|
||||
e.asset_type = entry.destination_asset;
|
||||
e.view_tag = entry.return_view_tag;
|
||||
e.anchor_enc = entry.return_anchor_enc;
|
||||
e.block_index = height;
|
||||
memcpy(e.enote_ephemeral_pubkey.data, entry.return_pubkey.data, sizeof(crypto::public_key));
|
||||
enotes.push_back(e);
|
||||
}
|
||||
|
||||
tx = store_carrot_to_coinbase_transaction_v1(enotes, std::string{}, cryptonote::transaction_type::PROTOCOL, height);
|
||||
tx.amount_burnt = 0;
|
||||
tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : TRANSACTION_VERSION_CARROT;
|
||||
tx.invalidate_hashes();
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
@@ -438,14 +413,29 @@ namespace cryptonote
|
||||
std::vector<crypto::public_key> additional_tx_public_keys;
|
||||
for (auto const& entry: protocol_data) {
|
||||
if (entry.type == cryptonote::transaction_type::STAKE) {
|
||||
|
||||
// PAYOUT
|
||||
LOG_PRINT_L2("Yield TX payout submitted " << entry.amount_burnt << entry.source_asset);
|
||||
|
||||
if (entry.is_carrot) {
|
||||
tx_out out;
|
||||
out.amount = entry.amount_burnt;
|
||||
out.target = txout_to_carrot_v1 {
|
||||
.key = entry.return_address,
|
||||
.asset_type = entry.destination_asset,
|
||||
.view_tag = entry.return_view_tag,
|
||||
.encrypted_janus_anchor = entry.return_anchor_enc,
|
||||
};
|
||||
|
||||
// Create the TX output for this refund
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
} else {
|
||||
// Create the TX output for this refund
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
|
||||
additional_tx_public_keys.push_back(entry.return_pubkey);
|
||||
tx.vout.push_back(out);
|
||||
}
|
||||
} else if (entry.type == cryptonote::transaction_type::AUDIT) {
|
||||
// PAYOUT
|
||||
LOG_PRINT_L2("Audit TX payout submitted " << entry.amount_burnt << entry.source_asset);
|
||||
@@ -469,14 +459,25 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, network_type nettype, const std::vector<hardfork_t>& hardforks, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) {
|
||||
carrot::janus_anchor_t get_deterministic_treasury_anchor_from_height(uint64_t height)
|
||||
{
|
||||
carrot::janus_anchor_t treasury_anchor{};
|
||||
for (int i = 0; i < 8; ++i)
|
||||
treasury_anchor.bytes[i] = (height >> (8 * i)) & 0xff;
|
||||
for (int i = 8; i < 16; ++i)
|
||||
treasury_anchor.bytes[i] = 0;
|
||||
return treasury_anchor;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, crypto::public_key& miner_reward_tx_key, transaction& tx, network_type nettype, const std::vector<hardfork_t>& hardforks, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) {
|
||||
|
||||
// Clear the TX contents
|
||||
tx.set_null();
|
||||
tx.type = cryptonote::transaction_type::MINER;
|
||||
|
||||
// check for treasury payouts
|
||||
auto[treasury_payout_exist, treasury_payout_index] = check_treasury_payout(nettype, height, hardforks, hard_fork_version);
|
||||
const auto treasury_payout_data = get_config(nettype).TREASURY_SAL1_MINT_OUTPUT_DATA;
|
||||
const bool treasury_payout_exists = (treasury_payout_data.count(height) == 1);
|
||||
|
||||
uint64_t block_reward;
|
||||
if(!get_block_reward(median_weight, current_block_weight, already_generated_coins, block_reward, hard_fork_version))
|
||||
@@ -496,13 +497,98 @@ namespace cryptonote
|
||||
{
|
||||
try
|
||||
{
|
||||
carrot::CarrotDestinationV1 destination;
|
||||
// miner destination
|
||||
carrot::CarrotDestinationV1 miner_destination;
|
||||
carrot::make_carrot_main_address_v1(miner_address.m_spend_public_key,
|
||||
miner_address.m_view_public_key,
|
||||
destination);
|
||||
miner_destination);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(!miner_destination.is_subaddress,
|
||||
"construct_miner_tx: subaddresses are not allowed in miner transactions");
|
||||
CHECK_AND_ASSERT_THROW_MES(miner_destination.payment_id == carrot::null_payment_id,
|
||||
"construct_miner_tx: integrated addresses are not allowed in miner transactions");
|
||||
|
||||
uint64_t stake_reward = block_reward / 5;
|
||||
tx = carrot::make_single_enote_carrot_coinbase_transaction_v1(destination, block_reward - stake_reward, height, extra_nonce);
|
||||
const bool do_new_split = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS);
|
||||
uint64_t treasury_reward = do_new_split ? (block_reward * BLOCK_REWARD_TREASURY_PCT / 100) : 0;
|
||||
uint64_t stake_reward = (block_reward - treasury_reward) * BLOCK_REWARD_STAKER_PCT / 100;
|
||||
uint64_t miner_reward = (block_reward - treasury_reward - stake_reward);
|
||||
|
||||
//miner enote
|
||||
const carrot::CarrotPaymentProposalV1 miner_proposal{
|
||||
.destination = miner_destination,
|
||||
.amount = miner_reward,
|
||||
.asset_type = "SAL1",
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
};
|
||||
|
||||
// Determine number of enotes: miner + optional treasury_reward + optional treasury_mint
|
||||
size_t num_enotes = 1;
|
||||
if (do_new_split) num_enotes++; // treasury reward output
|
||||
if (treasury_payout_exists) num_enotes++;
|
||||
std::vector<carrot::CarrotCoinbaseEnoteV1> enotes(num_enotes);
|
||||
carrot::get_coinbase_output_proposal_v1(miner_proposal, height, enotes[0]);
|
||||
|
||||
// STORE THE MINER TX_PUB_KEY NOW
|
||||
miner_reward_tx_key = carrot::raw_byte_convert<crypto::public_key>(enotes[0].enote_ephemeral_pubkey);
|
||||
|
||||
size_t enote_idx = 1;
|
||||
|
||||
// Add the treasury reward enote (25% of block reward) for HF11+
|
||||
if (do_new_split) {
|
||||
|
||||
//treasury address for HF11+ block reward split
|
||||
address_parse_info treasury_addr_info;
|
||||
bool treasury_ok = cryptonote::get_account_address_from_str(treasury_addr_info, nettype, get_config(nettype).TREASURY_ADDRESS_CARROT);
|
||||
CHECK_AND_ASSERT_MES(treasury_ok, false, "Failed to parse treasury address for block reward split"); // maybe more check can be added here, but it's enough for now (bcs validation)
|
||||
|
||||
carrot::CarrotDestinationV1 treasury_destination;
|
||||
carrot::make_carrot_main_address_v1(treasury_addr_info.address.m_spend_public_key,
|
||||
treasury_addr_info.address.m_view_public_key,
|
||||
treasury_destination);
|
||||
|
||||
// Derive a deterministic janus anchor from height so validators can independently recompute the expected treasury K_o
|
||||
const carrot::janus_anchor_t treasury_anchor = get_deterministic_treasury_anchor_from_height(height);
|
||||
const carrot::CarrotPaymentProposalV1 treasury_proposal{
|
||||
.destination = treasury_destination,
|
||||
.amount = treasury_reward,
|
||||
.asset_type = "SAL1",
|
||||
.randomness = treasury_anchor
|
||||
};
|
||||
|
||||
carrot::get_coinbase_output_proposal_v1(treasury_proposal, height, enotes[enote_idx]);
|
||||
enote_idx++;
|
||||
}
|
||||
|
||||
//
|
||||
if (treasury_payout_exists) {
|
||||
const auto [tx_public_key_str, onetime_address_str, anchor_enc_str, view_tag_str] = treasury_payout_data.at(height);
|
||||
mx25519_pubkey tx_public_key;
|
||||
CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(tx_public_key_str, tx_public_key), "fail to deserialize treasury tx public key");
|
||||
crypto::public_key onetime_address;
|
||||
CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(onetime_address_str, onetime_address), "fail to deserialize treasury tx onetime address");
|
||||
carrot::encrypted_janus_anchor_t anchor_enc;
|
||||
CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(anchor_enc_str, anchor_enc), "fail to deserialize treasury tx anchor_enc");
|
||||
carrot::view_tag_t view_tag;
|
||||
CHECK_AND_ASSERT_THROW_MES(epee::string_tools::hex_to_pod(view_tag_str, view_tag), "fail to deserialize treasury tx view_tag");
|
||||
|
||||
//
|
||||
carrot::CarrotCoinbaseEnoteV1 &treasury_enote = enotes[enote_idx];
|
||||
treasury_enote.onetime_address = onetime_address;
|
||||
treasury_enote.amount = TREASURY_SAL1_MINT_AMOUNT;
|
||||
treasury_enote.asset_type = "SAL1";
|
||||
treasury_enote.anchor_enc = anchor_enc;
|
||||
treasury_enote.view_tag = view_tag;
|
||||
treasury_enote.enote_ephemeral_pubkey = tx_public_key;
|
||||
treasury_enote.block_index = height;
|
||||
}
|
||||
|
||||
// Sort enotes by K_o
|
||||
std::sort(enotes.begin(), enotes.end(), [](const carrot::CarrotCoinbaseEnoteV1 &a, const carrot::CarrotCoinbaseEnoteV1 &b) {
|
||||
return a.onetime_address < b.onetime_address;
|
||||
});
|
||||
|
||||
tx = carrot::store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER, height);
|
||||
tx.version = (hard_fork_version >= HF_VERSION_ENABLE_TOKENS) ? TRANSACTION_VERSION_ENABLE_TOKENS : TRANSACTION_VERSION_CARROT;
|
||||
tx.amount_burnt = stake_reward;
|
||||
tx.invalidate_hashes();
|
||||
}
|
||||
@@ -517,6 +603,8 @@ namespace cryptonote
|
||||
|
||||
keypair txkey = keypair::generate(hw::get_device("default"));
|
||||
add_tx_pub_key_to_extra(tx, txkey.pub);
|
||||
// STORE THE MINER TX_PUB_KEY NOW
|
||||
miner_reward_tx_key = txkey.pub;
|
||||
if(!extra_nonce.empty())
|
||||
if(!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce))
|
||||
return false;
|
||||
@@ -560,6 +648,7 @@ namespace cryptonote
|
||||
case HF_VERSION_AUDIT2:
|
||||
case HF_VERSION_AUDIT2_PAUSE:
|
||||
case HF_VERSION_CARROT:
|
||||
case HF_VERSION_ENABLE_TOKENS:
|
||||
// SRCG: subtract 20% that will be rewarded to staking users
|
||||
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
|
||||
tx.amount_burnt = amount / 5;
|
||||
@@ -573,7 +662,7 @@ namespace cryptonote
|
||||
std::string asset_type = "SAL";
|
||||
if (hard_fork_version >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
asset_type = "SAL1";
|
||||
cryptonote::set_tx_out(amount, asset_type, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, !treasury_payout_exist, view_tag, out);
|
||||
cryptonote::set_tx_out(amount, asset_type, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
|
||||
tx.vout.push_back(out);
|
||||
|
||||
} else {
|
||||
@@ -586,27 +675,6 @@ namespace cryptonote
|
||||
|
||||
CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward);
|
||||
|
||||
// add the treasury payout if needed
|
||||
if (treasury_payout_exist) {
|
||||
std::vector<crypto::public_key> additional_tx_public_keys = {txkey.pub};
|
||||
const auto output_keys = get_config(nettype).TREASURY_SAL1_MINT_OUTPUT_KEYS;
|
||||
const auto keys = output_keys[treasury_payout_index];
|
||||
|
||||
crypto::public_key tx_key;
|
||||
CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(keys.first, tx_key), false, "fail to deserialize treasury tx key");
|
||||
crypto::public_key output_key;
|
||||
CHECK_AND_ASSERT_MES(epee::string_tools::hex_to_pod(keys.second, output_key), false, "fail to deserialize treasury output key");
|
||||
|
||||
// Create the TX output for this payout
|
||||
tx_out out;
|
||||
cryptonote::set_tx_out(TREASURY_SAL1_MINT_AMOUNT, "SAL1", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, output_key, false, crypto::view_tag{}, out);
|
||||
tx.vout.push_back(out);
|
||||
|
||||
// add tx pub key to tx extra
|
||||
additional_tx_public_keys.push_back(tx_key);
|
||||
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
|
||||
}
|
||||
|
||||
tx.version = 2;
|
||||
tx.vin.push_back(in);
|
||||
tx.invalidate_hashes();
|
||||
|
||||
@@ -68,15 +68,18 @@ namespace cryptonote
|
||||
uint8_t type;
|
||||
crypto::public_key P_change;
|
||||
crypto::public_key return_pubkey;
|
||||
carrot::view_tag_t return_view_tag;
|
||||
carrot::encrypted_janus_anchor_t return_anchor_enc;
|
||||
uint64_t origin_height;
|
||||
bool is_carrot;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------
|
||||
bool construct_protocol_tx(const size_t height, transaction& tx, std::vector<protocol_data_entry>& protocol_data, const uint8_t hf_version);
|
||||
//---------------------------------------------------------------
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, network_type nettype = network_type::FAKECHAIN, const std::vector<hardfork_t>& hardforks = {}, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
|
||||
carrot::janus_anchor_t get_deterministic_treasury_anchor_from_height(uint64_t height);
|
||||
//---------------------------------------------------------------
|
||||
std::tuple<bool, uint64_t> check_treasury_payout(network_type nettype, uint64_t height, const std::vector<hardfork_t>& hardforks, const uint8_t hf_version);
|
||||
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, crypto::public_key& miner_reward_tx_key, transaction& tx, network_type nettype = network_type::FAKECHAIN, const std::vector<hardfork_t>& hardforks = {}, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
|
||||
|
||||
struct tx_source_entry
|
||||
{
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "common/perf_timer.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "crypto/duration.h"
|
||||
#include "common/debugging.h"
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "txpool"
|
||||
@@ -266,6 +267,20 @@ namespace cryptonote
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the TX asset types
|
||||
if (!m_blockchain.check_tx_asset_types(tx, tvc)) {
|
||||
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid asset type(s)");
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// HERE BE DRAGONS!!!
|
||||
// Check that CREATE_TOKEN txs are unique in the pool
|
||||
if (tx.type == cryptonote::transaction_type::CREATE_TOKEN) {
|
||||
// TODO: ...scan the existing entries - requires either a registry of CREATE_TOKEN TXs, or to interatively process the pool
|
||||
}
|
||||
// LAND AHOY!!!
|
||||
|
||||
// assume failure during verification steps until success is certain
|
||||
tvc.m_verifivation_failed = true;
|
||||
@@ -1505,6 +1520,10 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that `transfer token` TXs have been paid for before accepting them into a block template
|
||||
if (!m_blockchain.is_tx_paid_for(lazy_tx()))
|
||||
return false;
|
||||
|
||||
//transaction is ok.
|
||||
return true;
|
||||
}
|
||||
@@ -1614,7 +1633,7 @@ namespace cryptonote
|
||||
//---------------------------------------------------------------------------------
|
||||
//---------------------------------------------------------------------------------
|
||||
//TODO: investigate whether boolean return is appropriate
|
||||
bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
|
||||
bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, std::vector<std::pair<protocol_tx_data_t, token_metadata_t>> &create_token_entries, uint8_t version)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_transactions_lock);
|
||||
CRITICAL_REGION_LOCAL1(m_blockchain);
|
||||
@@ -1630,7 +1649,6 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
size_t max_total_weight_pre_v5 = (130 * median_weight) / 100 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
size_t max_total_weight_v5 = 2 * median_weight - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
|
||||
size_t max_total_weight = version >= 5 ? max_total_weight_v5 : max_total_weight_pre_v5;
|
||||
@@ -1638,6 +1656,15 @@ namespace cryptonote
|
||||
|
||||
LOG_PRINT_L2("Filling block template, median weight " << median_weight << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
|
||||
|
||||
// Store list of tokens being created
|
||||
std::set<std::string> tokens;
|
||||
|
||||
// Get the list of already-created tokens that are in the DB
|
||||
std::map<std::string, cryptonote::token_metadata_t> mapTokens = m_blockchain.get_db().get_tokens();
|
||||
for (const auto &entry: mapTokens) {
|
||||
tokens.insert(entry.second.asset_type);
|
||||
}
|
||||
|
||||
LockedTXN lock(m_blockchain.get_db());
|
||||
|
||||
auto sorted_it = m_txs_by_fee_and_receive_time.begin();
|
||||
@@ -1749,6 +1776,49 @@ namespace cryptonote
|
||||
LOG_PRINT_L2(" key images already seen");
|
||||
continue;
|
||||
}
|
||||
if (version < HF_VERSION_CARROT && tx.version >= TRANSACTION_VERSION_CARROT)
|
||||
{
|
||||
LOG_PRINT_L2(" is a Carrot transaction - cannot be mined");
|
||||
continue;
|
||||
}
|
||||
if (version >= HF_VERSION_CARROT && tx.version < TRANSACTION_VERSION_CARROT)
|
||||
{
|
||||
LOG_PRINT_L2(" is not a Carrot transaction - cannot be mined");
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for ROLLUP TXs
|
||||
if (tx.type == cryptonote::transaction_type::ROLLUP)
|
||||
{
|
||||
if (version < HF_VERSION_ENABLE_TOKENS) {
|
||||
LOG_PRINT_L2(" is a ROLLUP transaction before they are permitted - cannot be mined");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// check and include create token entries
|
||||
if (tx.type == transaction_type::CREATE_TOKEN)
|
||||
{
|
||||
if (version < HF_VERSION_ENABLE_TOKENS) {
|
||||
LOG_PRINT_L2(" is a CREATE_TOKEN transaction before they are permitted - cannot be mined");
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string asset_type = "sal" + tx.token_metadata.asset_type;
|
||||
if (!cryptonote::is_valid_asset_type(asset_type)) {
|
||||
LOG_PRINT_L2(" is a CREATE_TOKEN transaction with an invalid asset_type - cannot be mined");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if token is already being created
|
||||
if (tokens.find(tx.token_metadata.asset_type) != tokens.end()) {
|
||||
LOG_PRINT_L2(" is a CREATE_TOKEN transaction with an asset_type already in the block template - cannot be mined");
|
||||
continue;
|
||||
}
|
||||
|
||||
tokens.insert(tx.token_metadata.asset_type);
|
||||
create_token_entries.push_back(std::make_pair(tx.protocol_tx_data, tx.token_metadata));
|
||||
}
|
||||
|
||||
bl.tx_hashes.push_back(sorted_it->second);
|
||||
total_weight += meta.weight;
|
||||
|
||||
@@ -226,11 +226,12 @@ namespace cryptonote
|
||||
* @param total_weight return-by-reference the total weight of the new block
|
||||
* @param fee return-by-reference the total of fees from the included transactions
|
||||
* @param expected_reward return-by-reference the total reward awarded to the miner finding this block, including transaction fees
|
||||
* @param create_token_entries list of create coin entries to include in protocol tx
|
||||
* @param version hard fork version to use for consensus rules
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version);
|
||||
bool fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, std::vector<std::pair<protocol_tx_data_t, token_metadata_t>> &create_token_entries, uint8_t version);
|
||||
|
||||
/**
|
||||
* @brief get a list of all transactions in the pool
|
||||
|
||||
@@ -187,7 +187,7 @@ bool ver_rct_non_semantics_simple_cached
|
||||
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions
|
||||
// holds true in the future, enable the verification hash by modifying the `untested_tx`
|
||||
// condition below.
|
||||
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeSalviumOne;
|
||||
const bool untested_tx = tx.version > TRANSACTION_VERSION_ENABLE_TOKENS || tx.rct_signatures.type > rct::RCTTypeSalviumOne;
|
||||
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
|
||||
|
||||
// Don't cache older (or newer) rctSig types
|
||||
|
||||
@@ -54,6 +54,8 @@ namespace cryptonote
|
||||
STAKE = 6,
|
||||
RETURN = 7,
|
||||
AUDIT = 8,
|
||||
MAX = 8
|
||||
CREATE_TOKEN = 9,
|
||||
ROLLUP = 10,
|
||||
MAX = 10
|
||||
};
|
||||
}
|
||||
|
||||
@@ -374,6 +374,8 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_carrot = m_executor.current_hard_fork_version() >= HF_VERSION_CARROT;
|
||||
|
||||
cryptonote::address_parse_info info;
|
||||
cryptonote::network_type nettype = cryptonote::MAINNET;
|
||||
if(!cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, args.front()))
|
||||
@@ -420,6 +422,13 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
|
||||
tools::fail_msg_writer() << "subaddress for mining reward is not yet supported!" << std::endl;
|
||||
return true;
|
||||
}
|
||||
if (info.is_carrot && !is_carrot) {
|
||||
tools::fail_msg_writer() << "mining to Carrot wallet address, but Carrot isn't supported yet" << std::endl;
|
||||
return true;
|
||||
} else if (!info.is_carrot && is_carrot) {
|
||||
tools::fail_msg_writer() << "mining to CryptoNote wallet address, but Carrot wallet address is required" << std::endl;
|
||||
return true;
|
||||
}
|
||||
if(nettype != cryptonote::MAINNET)
|
||||
std::cout << "Mining to a " << (nettype == cryptonote::TESTNET ? "testnet" : "stagenet") << " address, make sure this is intentional!" << std::endl;
|
||||
uint64_t threads_count = 1;
|
||||
@@ -470,7 +479,7 @@ bool t_command_parser_executor::start_mining(const std::vector<std::string>& arg
|
||||
}
|
||||
}
|
||||
|
||||
m_executor.start_mining(info.address, threads_count, nettype, do_background_mining, ignore_battery);
|
||||
m_executor.start_mining(info.address, threads_count, nettype, do_background_mining, ignore_battery, info.is_carrot);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+2
-1
@@ -149,7 +149,8 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
|
||||
|
||||
//Prepare genesis_tx
|
||||
cryptonote::transaction tx_genesis;
|
||||
cryptonote::construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().m_account_address, tx_genesis, (network_type)nettype, {}, blobdata(), 999, 1);
|
||||
crypto::public_key miner_reward_tx_key = crypto::null_pkey;
|
||||
cryptonote::construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().m_account_address, miner_reward_tx_key, tx_genesis, (network_type)nettype, {}, blobdata(), 999, 1);
|
||||
std::cout << "Object:" << std::endl;
|
||||
std::cout << obj_to_json_str(tx_genesis) << std::endl << std::endl;
|
||||
|
||||
|
||||
@@ -1352,7 +1352,7 @@ bool t_rpc_command_executor::print_transaction_pool_stats() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, cryptonote::network_type nettype, bool do_background_mining, bool ignore_battery) {
|
||||
bool t_rpc_command_executor::start_mining(cryptonote::account_public_address address, uint64_t num_threads, cryptonote::network_type nettype, bool do_background_mining, bool ignore_battery, bool is_carrot) {
|
||||
cryptonote::COMMAND_RPC_START_MINING::request req;
|
||||
cryptonote::COMMAND_RPC_START_MINING::response res;
|
||||
req.miner_address = cryptonote::get_account_address_as_str(nettype, false, address);
|
||||
@@ -1650,6 +1650,34 @@ bool t_rpc_command_executor::in_peers(bool set, uint32_t limit)
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t t_rpc_command_executor::current_hard_fork_version()
|
||||
{
|
||||
cryptonote::COMMAND_RPC_HARD_FORK_INFO::request req;
|
||||
cryptonote::COMMAND_RPC_HARD_FORK_INFO::response res;
|
||||
std::string fail_message = "Unsuccessful";
|
||||
epee::json_rpc::error error_resp;
|
||||
|
||||
req.version = 0;
|
||||
|
||||
if (m_is_rpc)
|
||||
{
|
||||
if (!m_rpc_client->json_rpc_request(req, res, "hard_fork_info", fail_message.c_str()))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_rpc_server->on_hard_fork_info(req, res, error_resp) || res.status != CORE_RPC_STATUS_OK)
|
||||
{
|
||||
tools::fail_msg_writer() << make_error(fail_message, res.status);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return res.version;
|
||||
}
|
||||
|
||||
bool t_rpc_command_executor::hard_fork_info(uint8_t version)
|
||||
{
|
||||
cryptonote::COMMAND_RPC_HARD_FORK_INFO::request req;
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
|
||||
bool print_transaction_pool_stats();
|
||||
|
||||
bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, cryptonote::network_type nettype, bool do_background_mining = false, bool ignore_battery = false);
|
||||
bool start_mining(cryptonote::account_public_address address, uint64_t num_threads, cryptonote::network_type nettype, bool do_background_mining = false, bool ignore_battery = false, bool is_carrot = false);
|
||||
|
||||
bool stop_mining();
|
||||
|
||||
@@ -128,6 +128,8 @@ public:
|
||||
|
||||
bool in_peers(bool set, uint32_t limit);
|
||||
|
||||
uint8_t current_hard_fork_version();
|
||||
|
||||
bool hard_fork_info(uint8_t version);
|
||||
|
||||
bool print_bans();
|
||||
|
||||
@@ -202,6 +202,10 @@ namespace hw {
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
crypto::signature &sig) = 0;
|
||||
|
||||
virtual void generate_carrot_tx_proof(const crypto::hash &prefix_hash,
|
||||
const crypto::public_key &R, const crypto::public_key &A, const boost::optional<crypto::public_key> &B, const crypto::public_key &D, const crypto::secret_key &r,
|
||||
const crypto::secret_key &a, crypto::signature &sig) = 0;
|
||||
|
||||
virtual bool open_tx(crypto::secret_key &tx_key) = 0;
|
||||
|
||||
virtual void get_transaction_prefix_hash(const cryptonote::transaction_prefix& tx, crypto::hash& h) = 0;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user