Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e2bc467618 | |||
| cb3f1905ed | |||
| 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 |
@@ -1,4 +1,4 @@
|
||||
# Salvium Zero v0.9.6
|
||||
# Salvium Zero v0.9.9
|
||||
|
||||
Copyright (c) 2023-2024, Salvium
|
||||
Portions Copyright (c) 2014-2023, The Monero Project
|
||||
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
|
||||
|
||||
```bash
|
||||
cd salvium
|
||||
git checkout v0.9.6
|
||||
git checkout v0.9.9
|
||||
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 v0.9.9
|
||||
```
|
||||
|
||||
* 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. 'v0.9.9'. 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 v0.9.9
|
||||
```
|
||||
|
||||
* 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)
|
||||
|
||||
@@ -207,6 +207,17 @@ typedef struct yield_tx_info {
|
||||
crypto::public_key return_pubkey;
|
||||
} yield_tx_info;
|
||||
|
||||
typedef struct yield_tx_info_carrot {
|
||||
uint8_t version;
|
||||
uint64_t block_height;
|
||||
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;
|
||||
|
||||
#define DBF_SAFE 1
|
||||
#define DBF_FAST 2
|
||||
#define DBF_FASTEST 4
|
||||
@@ -1924,6 +1935,8 @@ 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;
|
||||
|
||||
|
||||
/**
|
||||
* @brief set whether or not to automatically remove logs
|
||||
|
||||
@@ -298,6 +298,7 @@ const char* const LMDB_YIELD_TXS = "yield_txs";
|
||||
const char* const LMDB_YIELD_BLOCKS = "yield_blocks";
|
||||
const char* const LMDB_AUDIT_TXS = "audit_txs";
|
||||
const char* const LMDB_AUDIT_BLOCKS = "audit_blocks";
|
||||
const char* const LMDB_CARROT_YIELD_TXS = "carrot_yield_txs";
|
||||
|
||||
const char zerokey[8] = {0};
|
||||
const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey };
|
||||
@@ -947,6 +948,43 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BlockchainLMDB::get_carrot_yield_tx_info(const uint64_t height, std::vector<yield_tx_info_carrot>& yti_container) const {
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
check_open();
|
||||
|
||||
// Clear the container
|
||||
yti_container.clear();
|
||||
|
||||
// Query for the (presumably matured) YIELD_TX_INFO information
|
||||
TXN_PREFIX_RDONLY();
|
||||
RCURSOR(carrot_yield_txs);
|
||||
|
||||
MDB_val v;
|
||||
MDB_val_set(k, height);
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
while (1)
|
||||
{
|
||||
int ret = mdb_cursor_get(m_cur_carrot_yield_txs, &k, &v, op);
|
||||
op = MDB_NEXT_DUP;
|
||||
if (ret == MDB_NOTFOUND)
|
||||
break;
|
||||
if (ret)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to enumerate yield TX info: ", ret).c_str()));
|
||||
|
||||
// Get the data
|
||||
yield_tx_info_carrot *p = (yield_tx_info_carrot*)v.mv_data;
|
||||
// Push result back into the container
|
||||
yti_container.emplace_back(*p);
|
||||
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
|
||||
yti_container.back().block_height = height;
|
||||
}
|
||||
|
||||
TXN_POSTFIX_RDONLY();
|
||||
|
||||
// Return success to caller
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, uint64_t audit_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
|
||||
{
|
||||
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
|
||||
@@ -1215,6 +1253,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_txs)
|
||||
CURSOR(audit_txs)
|
||||
CURSOR(carrot_yield_txs)
|
||||
|
||||
MDB_val_set(val_tx_id, tx_id);
|
||||
MDB_val_set(val_h, tx_hash);
|
||||
@@ -1321,7 +1360,12 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
if (tx.type == cryptonote::transaction_type::BURN ||
|
||||
tx.type == cryptonote::transaction_type::CONVERT ||
|
||||
tx.type == cryptonote::transaction_type::STAKE ||
|
||||
tx.type == cryptonote::transaction_type::AUDIT ||
|
||||
tx.type == cryptonote::transaction_type::TRANSFER)
|
||||
{
|
||||
|
||||
// Get the current tally value for the source currency type
|
||||
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
|
||||
@@ -1390,10 +1434,44 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
|
||||
}
|
||||
}
|
||||
|
||||
// Is there yield_tx data to add?
|
||||
if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
|
||||
// Is there yield_tx data to add?
|
||||
if (tx.version >= TRANSACTION_VERSION_CARROT && tx.type == cryptonote::transaction_type::STAKE)
|
||||
{
|
||||
// Create the object we are going to write to the database
|
||||
yield_tx_info_carrot yield_data;
|
||||
yield_data.block_height = m_height;
|
||||
yield_data.tx_hash = tx_hash;
|
||||
yield_data.return_pubkey = tx.protocol_tx_data.return_pubkey;
|
||||
yield_data.return_address = tx.protocol_tx_data.return_address;
|
||||
yield_data.return_view_tag = tx.protocol_tx_data.return_view_tag;
|
||||
yield_data.return_anchor_enc = tx.protocol_tx_data.return_anchor_enc;
|
||||
yield_data.locked_coins = tx.amount_burnt;
|
||||
|
||||
// Because LMDB is shockingly bad at handling duplicates, we have resorted to using a counter of elements
|
||||
// in the first element of the struct.
|
||||
MDB_val data;
|
||||
MDB_val_set(val_height, m_height);
|
||||
result = mdb_cursor_get(m_cur_carrot_yield_txs, &val_height, &data, MDB_SET);
|
||||
if (!result)
|
||||
{
|
||||
mdb_size_t num_elems = 0;
|
||||
result = mdb_cursor_count(m_cur_carrot_yield_txs, &num_elems);
|
||||
if (result)
|
||||
throw0(DB_ERROR(std::string("Failed to get number of yield TXs for height: ").append(mdb_strerror(result)).c_str()));
|
||||
yield_data.block_height = num_elems;
|
||||
}
|
||||
else if (result != MDB_NOTFOUND)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str()));
|
||||
else
|
||||
yield_data.block_height = 0;
|
||||
|
||||
// Now we know how many there are, write out the data to the DB
|
||||
MDB_val_set(val_yield_tx_data, yield_data);
|
||||
result = mdb_cursor_put(m_cur_carrot_yield_txs, &val_height, &val_yield_tx_data, MDB_APPENDDUP);
|
||||
if (result)
|
||||
throw0(DB_ERROR(lmdb_error("Failed to add tx carrot yield data to db transaction: ", result).c_str()));
|
||||
} else if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
// Create the object we are going to write to the database
|
||||
yield_tx_info yield_data;
|
||||
yield_data.block_height = m_height;
|
||||
@@ -1444,7 +1522,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
if (result)
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx yield data to db transaction: ", result).c_str() ));
|
||||
}
|
||||
|
||||
|
||||
// Is there audit_tx data to add?
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
@@ -1498,7 +1576,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
|
||||
if (result)
|
||||
throw0(DB_ERROR( lmdb_error("Failed to add tx audit data to db transaction: ", result).c_str() ));
|
||||
}
|
||||
|
||||
|
||||
return tx_id;
|
||||
}
|
||||
|
||||
@@ -1522,6 +1600,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
CURSOR(circ_supply_tally)
|
||||
CURSOR(yield_txs)
|
||||
CURSOR(audit_txs)
|
||||
CURSOR(carrot_yield_txs)
|
||||
|
||||
MDB_val_set(val_h, tx_hash);
|
||||
|
||||
@@ -1720,7 +1799,28 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
|
||||
}
|
||||
|
||||
// Is there yield_tx data to remove?
|
||||
if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
if (tx.version >= TRANSACTION_VERSION_CARROT && tx.type == cryptonote::transaction_type::STAKE) {
|
||||
// Remove any yield_tx data for this transaction
|
||||
MDB_val_set(val_height, m_height);
|
||||
MDB_val v;
|
||||
MDB_cursor_op op = MDB_SET;
|
||||
while (1) {
|
||||
result = mdb_cursor_get(m_cur_carrot_yield_txs, &val_height, &v, op);
|
||||
if (result == MDB_NOTFOUND) {
|
||||
throw1(DB_ERROR("Failed to locate carrot yield tx for removal from db transaction"));
|
||||
} else if (result) {
|
||||
throw1(DB_ERROR(lmdb_error("Failed to locate carrot yield_tx data for removal: ", result).c_str()));
|
||||
}
|
||||
op = MDB_NEXT_DUP;
|
||||
const yield_tx_info_carrot yti = *(const yield_tx_info_carrot*)v.mv_data;
|
||||
if (yti.tx_hash == tx_hash) {
|
||||
result = mdb_cursor_del(m_cur_carrot_yield_txs, 0);
|
||||
if (result)
|
||||
throw1(DB_ERROR(lmdb_error("Failed to add removal of carrot yield_tx data to db transaction: ", result).c_str()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tx.type == cryptonote::transaction_type::STAKE) {
|
||||
// Remove any yield_tx data for this transaction
|
||||
MDB_val_set(val_height, m_height);
|
||||
MDB_val v;
|
||||
@@ -2284,10 +2384,12 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
|
||||
lmdb_db_open(txn, LMDB_YIELD_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_yield_txs, "Failed to open db handle for m_yield_txs");
|
||||
lmdb_db_open(txn, LMDB_YIELD_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_yield_blocks, "Failed to open db handle for m_yield_blocks");
|
||||
|
||||
|
||||
lmdb_db_open(txn, LMDB_AUDIT_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_audit_txs, "Failed to open db handle for m_audit_txs");
|
||||
lmdb_db_open(txn, LMDB_AUDIT_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_audit_blocks, "Failed to open db handle for m_audit_blocks");
|
||||
|
||||
lmdb_db_open(txn, LMDB_CARROT_YIELD_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_carrot_yield_txs, "Failed to open db handle for m_carrot_yield_txs");
|
||||
|
||||
mdb_set_dupsort(txn, m_spent_keys, compare_hash32);
|
||||
mdb_set_dupsort(txn, m_block_heights, compare_hash32);
|
||||
mdb_set_dupsort(txn, m_tx_indices, compare_hash32);
|
||||
@@ -2312,6 +2414,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
|
||||
|
||||
mdb_set_dupsort(txn, m_yield_txs, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_audit_txs, compare_uint64);
|
||||
mdb_set_dupsort(txn, m_carrot_yield_txs, compare_uint64);
|
||||
|
||||
if (!(mdb_flags & MDB_RDONLY))
|
||||
{
|
||||
@@ -2497,6 +2600,8 @@ void BlockchainLMDB::reset()
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_txs: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_audit_blocks, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_blocks: ", result).c_str()));
|
||||
if (auto result = mdb_drop(txn, m_carrot_yield_txs, 0))
|
||||
throw0(DB_ERROR(lmdb_error("Failed to drop m_carrot_yield_txs: ", result).c_str()));
|
||||
|
||||
// init with current version
|
||||
MDB_val_str(k, "version");
|
||||
|
||||
@@ -80,6 +80,7 @@ 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_txn_cursors;
|
||||
|
||||
@@ -108,6 +109,7 @@ 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
|
||||
|
||||
typedef struct mdb_rflags
|
||||
{
|
||||
@@ -137,6 +139,7 @@ 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;
|
||||
} mdb_rflags;
|
||||
|
||||
typedef struct mdb_threadinfo
|
||||
@@ -474,6 +477,7 @@ 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;
|
||||
|
||||
private:
|
||||
MDB_env* m_env;
|
||||
@@ -511,10 +515,12 @@ 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;
|
||||
|
||||
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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -58,14 +58,14 @@ CarrotDestinationV1 carrot_and_legacy_account::cryptonote_address(const payment_
|
||||
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,
|
||||
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(legacy_acb.get_keys().m_account_address.m_spend_public_key,
|
||||
legacy_acb.get_keys().m_account_address.m_view_public_key,
|
||||
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;
|
||||
@@ -80,15 +80,15 @@ CarrotDestinationV1 carrot_and_legacy_account::subaddress(const subaddress_index
|
||||
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();
|
||||
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(carrot_account_spend_pubkey,
|
||||
carrot_account_view_pubkey,
|
||||
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,
|
||||
@@ -96,7 +96,7 @@ CarrotDestinationV1 carrot_and_legacy_account::subaddress(const subaddress_index
|
||||
break;
|
||||
case AddressDeriveType::PreCarrot:
|
||||
cnaddr =
|
||||
lkeys.m_device->get_subaddress(lkeys, {subaddress_index.index.major, subaddress_index.index.minor});
|
||||
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,
|
||||
@@ -110,17 +110,25 @@ CarrotDestinationV1 carrot_and_legacy_account::subaddress(const subaddress_index
|
||||
return addr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> carrot_and_legacy_account::subaddress_map_cn() const
|
||||
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)
|
||||
if (p.second.derive_type == AddressDeriveType::PreCarrot)
|
||||
res.emplace(p.first, cryptonote::subaddress_index{p.second.index.major, p.second.index.minor});
|
||||
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");
|
||||
"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,
|
||||
@@ -130,7 +138,7 @@ void carrot_and_legacy_account::opening_for_subaddress(const subaddress_index_ex
|
||||
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();
|
||||
const cryptonote::account_keys &keys = get_keys();
|
||||
|
||||
crypto::secret_key address_index_generator;
|
||||
crypto::secret_key subaddress_scalar;
|
||||
@@ -140,12 +148,12 @@ void carrot_and_legacy_account::opening_for_subaddress(const subaddress_index_ex
|
||||
{
|
||||
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);
|
||||
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(carrot_account_spend_pubkey, address_index_generator, major_index, minor_index, subaddress_scalar);
|
||||
make_carrot_subaddress_scalar(keys.m_carrot_account_address.m_spend_public_key, address_index_generator, major_index, minor_index, subaddress_scalar);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -154,19 +162,19 @@ void carrot_and_legacy_account::opening_for_subaddress(const subaddress_index_ex
|
||||
}
|
||||
|
||||
// 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));
|
||||
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(k_prove_spend), to_bytes(subaddress_scalar));
|
||||
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
|
||||
? lkeys.get_device().get_subaddress_secret_key(lkeys.m_view_secret_key, {major_index, minor_index})
|
||||
? 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(lkeys.m_spend_secret_key), to_bytes(subaddress_extension));
|
||||
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));
|
||||
@@ -284,7 +292,7 @@ void carrot_and_legacy_account::generate_subaddress_map()
|
||||
{
|
||||
for (const AddressDeriveType derive_type : derive_types)
|
||||
{
|
||||
const subaddress_index_extended subaddr_index{{major_index, minor_index}, derive_type};
|
||||
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});
|
||||
}
|
||||
@@ -292,26 +300,63 @@ void carrot_and_legacy_account::generate_subaddress_map()
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::generate(const AddressDeriveType default_derive_type)
|
||||
crypto::secret_key carrot_and_legacy_account::generate(
|
||||
const crypto::secret_key& recovery_key,
|
||||
bool recover,
|
||||
bool two_random,
|
||||
const AddressDeriveType default_derive_type)
|
||||
{
|
||||
//legacy_acb.generate();
|
||||
// generate the legacy keys
|
||||
crypto::secret_key retval = cryptonote::account_base::generate(recovery_key, recover, two_random);
|
||||
|
||||
//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);
|
||||
// generate carrot keys
|
||||
set_carrot_keys(default_derive_type);
|
||||
|
||||
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);
|
||||
return retval;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
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
|
||||
);
|
||||
|
||||
// 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
|
||||
);
|
||||
|
||||
this->default_derive_type = default_derive_type;
|
||||
|
||||
generate_subaddress_map();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
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}});
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
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;
|
||||
@@ -28,11 +28,11 @@
|
||||
|
||||
#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 "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"
|
||||
@@ -43,30 +43,43 @@ static constexpr std::uint32_t MAX_SUBADDRESS_MINOR_INDEX = 20;
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
struct carrot_and_legacy_account
|
||||
|
||||
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::key_image key_image;
|
||||
crypto::secret_key x;
|
||||
crypto::secret_key y;
|
||||
|
||||
return_output_info_t(
|
||||
const input_context_t &input_context,
|
||||
const crypto::public_key &K_o,
|
||||
const crypto::public_key &K_change,
|
||||
const crypto::key_image &key_image,
|
||||
const crypto::secret_key &x,
|
||||
const crypto::secret_key &y):
|
||||
input_context(input_context),
|
||||
K_o(K_o),
|
||||
K_change(K_change),
|
||||
key_image(key_image),
|
||||
x(x),
|
||||
y(y) {}
|
||||
};
|
||||
|
||||
|
||||
class carrot_and_legacy_account : public cryptonote::account_base
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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(): 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)
|
||||
{}
|
||||
|
||||
carrot_and_legacy_account(const carrot_and_legacy_account &k) = delete;
|
||||
@@ -80,7 +93,9 @@ namespace carrot
|
||||
|
||||
CarrotDestinationV1 subaddress(const subaddress_index_extended &subaddress_index) const;
|
||||
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddress_map_cn() 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,
|
||||
@@ -110,8 +125,24 @@ namespace carrot
|
||||
|
||||
void generate_subaddress_map();
|
||||
|
||||
void generate(const AddressDeriveType default_derive_type = AddressDeriveType::Carrot);
|
||||
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 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;
|
||||
};
|
||||
}
|
||||
@@ -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 = 128;
|
||||
|
||||
// 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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -211,6 +211,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_return = H_32(s_sr || input_context || Ko)
|
||||
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 +232,37 @@ 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_enc_pubkey_out)
|
||||
{
|
||||
// K_return = k_return G + k_idx T
|
||||
crypto::secret_key k_return;
|
||||
crypto::secret_key k_idx = crypto::null_skey;
|
||||
encrypted_return_pubkey_t return_pub;
|
||||
s_view_balance_dev->make_internal_return_privkey(input_context, onetime_address, k_return);
|
||||
make_sparc_return_index(to_bytes(onetime_address), input_context, onetime_address, idx, k_idx);
|
||||
rct::key K_return;
|
||||
rct::addKeys2(K_return,
|
||||
rct::sk2rct(k_return),
|
||||
rct::sk2rct(k_idx),
|
||||
rct::pk2rct(crypto::get_T()));
|
||||
//K_return = rct::scalarmult8(K_return);
|
||||
if (!rct::isInMainSubgroup(K_return))
|
||||
throw std::runtime_error("K_return is not in main subgroup");
|
||||
static_assert(sizeof(K_return.bytes) == sizeof(return_pub.bytes), "Size mismatch");
|
||||
memcpy(return_pub.bytes, K_return.bytes, sizeof(encrypted_return_pubkey_t));
|
||||
|
||||
// return_enc = return_pub ^ m_return
|
||||
encrypted_return_pubkey_t m_return;
|
||||
make_sparc_return_pubkey_encryption_mask(s_sender_receiver_unctx, input_context, onetime_address, m_return);
|
||||
return_enc_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)
|
||||
|
||||
@@ -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 k_idx, given non-secret data
|
||||
* k_idx = 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
|
||||
* outparam: return_index_out - k_idx
|
||||
*/
|
||||
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,22 @@ 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
|
||||
* param: idx
|
||||
* 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)
|
||||
|
||||
@@ -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,11 @@ 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) {
|
||||
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,6 +210,9 @@ 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)
|
||||
{
|
||||
@@ -210,10 +220,19 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
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) {
|
||||
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 +242,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
|
||||
@@ -255,6 +279,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 +296,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 +319,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
|
||||
@@ -327,7 +364,7 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
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");
|
||||
invalid_point, "this set contains an invalid onetime address");
|
||||
}
|
||||
|
||||
// assert unique and non-trivial k_a
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -170,6 +170,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 +178,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 +204,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/*idx*/,
|
||||
return_pubkey_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -257,6 +268,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 +280,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 +288,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 +304,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 +324,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 +332,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 +340,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 +387,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 +396,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 +404,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;
|
||||
@@ -401,13 +423,15 @@ void get_output_proposal_special_v1(const CarrotPaymentProposalSelfSendV1 &propo
|
||||
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.return_enc = crypto::rand<carrot::encrypted_return_pubkey_t>();
|
||||
output_enote_out.amount = proposal.amount;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
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 +449,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 +488,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
|
||||
@@ -529,7 +561,39 @@ void get_output_proposal_internal_v1(const CarrotPaymentProposalSelfSendV1 &prop
|
||||
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.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) {
|
||||
// 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,
|
||||
|
||||
@@ -133,6 +133,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);
|
||||
/**
|
||||
@@ -144,9 +145,10 @@ void get_output_proposal_normal_v1(const CarrotPaymentProposalV1 &proposal,
|
||||
* outparam: encrypted_payment_id_out - pid_enc
|
||||
*/
|
||||
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);
|
||||
/**
|
||||
* brief: get_output_proposal_special_v1 - convert the carrot proposal to an output proposal (external selfsend)
|
||||
* param: proposal -
|
||||
@@ -173,6 +175,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
|
||||
|
||||
+204
-20
@@ -34,6 +34,11 @@
|
||||
//local headers
|
||||
#include "destination.h"
|
||||
#include "enote_utils.h"
|
||||
extern "C"
|
||||
{
|
||||
#include "crypto/crypto-ops.h"
|
||||
}
|
||||
#include "crypto/generators.h"
|
||||
#include "ringct/rctOps.h"
|
||||
#include "scan_unsafe.h"
|
||||
|
||||
@@ -70,6 +75,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,
|
||||
@@ -361,43 +464,124 @@ 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)
|
||||
{
|
||||
// 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);
|
||||
|
||||
bool normal_change_found = true;
|
||||
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);
|
||||
|
||||
// make k_idx
|
||||
crypto::secret_key k_idx = crypto::null_skey;
|
||||
uint64_t idx = 0;
|
||||
make_sparc_return_index(to_bytes(output_key), input_context, output_key, idx, k_idx);
|
||||
|
||||
// compute 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()));
|
||||
//K_return = rct::scalarmult8(K_return);
|
||||
|
||||
// compute K_r = K_return + K_o
|
||||
crypto::public_key K_r = rct::rct2pk(rct::addKeys(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::secret_key sum_t;
|
||||
sc_add(to_bytes(sum_t), to_bytes(sender_extension_t_out), to_bytes(k_idx));
|
||||
crypto::key_image key_image = account.derive_key_image(
|
||||
account.get_keys().m_carrot_account_address.m_spend_public_key,
|
||||
sum_g,
|
||||
sum_t,
|
||||
K_r
|
||||
);
|
||||
|
||||
crypto::secret_key x, y;
|
||||
account.try_searching_for_opening_for_onetime_address(
|
||||
account.get_keys().m_carrot_account_address.m_spend_public_key,
|
||||
sum_g,
|
||||
sum_t,
|
||||
x,
|
||||
y
|
||||
);
|
||||
|
||||
// save the input context & change output key
|
||||
account.insert_return_output_info({{K_r, {input_context, output_key, enote.onetime_address, key_image, x, y}}});
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -59,10 +59,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)
|
||||
{
|
||||
@@ -197,18 +197,32 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
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 carrot::RCTOutputEnoteProposal &return_enote,
|
||||
const encrypted_payment_id_t encrypted_payment_id)
|
||||
{
|
||||
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());
|
||||
|
||||
cryptonote::transaction tx;
|
||||
tx.pruned = true;
|
||||
tx.version = 2;
|
||||
tx.unlock_time = 0;
|
||||
tx.source_asset_type = "SAL1";
|
||||
tx.destination_asset_type = "SAL1";
|
||||
tx.version = 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_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;
|
||||
@@ -249,6 +263,23 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
|
||||
//C_a
|
||||
tx.rct_signatures.outPk.push_back(rct::ctkey{rct::key{}, enote.amount_commitment});
|
||||
|
||||
//K_return
|
||||
if (tx_type != cryptonote::transaction_type::STAKE) {
|
||||
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.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;
|
||||
}
|
||||
|
||||
//ephemeral pubkeys: D_e
|
||||
@@ -324,6 +355,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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -104,6 +105,10 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
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 RCTOutputEnoteProposal &return_enote,
|
||||
const encrypted_payment_id_t encrypted_payment_id);
|
||||
/**
|
||||
* brief: try_load_carrot_enote_from_transaction_v1 - load one non-coinbase Carrot enote from a cryptonote::transaction
|
||||
|
||||
@@ -326,15 +326,25 @@ std::vector<std::size_t> get_input_counts_in_preferred_order()
|
||||
// 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,
|
||||
//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 == 128,
|
||||
"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, 128, 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, 65, 66, 67, 68, 69, 70, 71, 72, 73,
|
||||
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
|
||||
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
|
||||
117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127};
|
||||
else
|
||||
return {1, 2, 4, 8, 3, 5, 6, 7};
|
||||
return {1, 2, 4, 8, 16, 32, 64, 128, 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, 65, 66, 67, 68, 69, 70, 71, 72, 73,
|
||||
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
|
||||
98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
|
||||
117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127};
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
select_inputs_func_t make_single_transfer_input_selector(
|
||||
@@ -388,7 +398,7 @@ select_inputs_func_t make_single_transfer_input_selector(
|
||||
|
||||
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);
|
||||
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 +423,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);
|
||||
if (!max_usable_money.first)
|
||||
continue;
|
||||
else if (max_usable_money.second < required_money_by_input_count.at(max_usable_money.first))
|
||||
|
||||
@@ -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,6 +128,10 @@ void make_pruned_transaction_from_proposal_v1(const CarrotTransactionProposalV1
|
||||
tx_proposal.key_images_sorted,
|
||||
tx_proposal.sources,
|
||||
tx_proposal.fee,
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
0, // tx_amount_burnt
|
||||
{}, // change_masks
|
||||
{}, // return_enote
|
||||
encrypted_payment_id);
|
||||
|
||||
// add extra payload and sort
|
||||
|
||||
@@ -84,6 +84,10 @@ 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;
|
||||
|
||||
/// 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
|
||||
|
||||
@@ -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);
|
||||
@@ -216,8 +217,19 @@ void make_carrot_transaction_proposal_v1(const std::vector<CarrotPaymentProposal
|
||||
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)
|
||||
{
|
||||
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 +238,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
|
||||
tx_proposal_out.tx_type = tx_type;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void make_carrot_transaction_proposal_v1_transfer(
|
||||
@@ -234,6 +249,7 @@ 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,
|
||||
@@ -268,7 +284,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,
|
||||
@@ -314,6 +331,15 @@ void make_carrot_transaction_proposal_v1_transfer(
|
||||
selfsend_payment_proposals.back().proposal.amount =
|
||||
boost::numeric_cast<rct::xmr_amount>(implicit_change_amount);
|
||||
|
||||
// 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)
|
||||
{
|
||||
selfsend_payment_proposals.back().proposal.enote_ephemeral_pubkey =
|
||||
selfsend_payment_proposals.front().proposal.enote_ephemeral_pubkey;
|
||||
selfsend_payment_proposals.erase(selfsend_payment_proposals.begin());
|
||||
}
|
||||
|
||||
// deduct an even fee amount from all subtractable outputs
|
||||
const size_t num_subtractble_normal = subtractable_normal_payment_proposals.size();
|
||||
const size_t num_subtractable_selfsend = subtractable_selfsend_payment_proposals.size();
|
||||
@@ -385,6 +411,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,6 +425,7 @@ 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,
|
||||
@@ -477,6 +505,7 @@ void make_carrot_transaction_proposal_v1_sweep(
|
||||
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,6 +207,7 @@ 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,
|
||||
@@ -212,6 +221,7 @@ 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,
|
||||
|
||||
@@ -276,6 +276,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};
|
||||
// change this code into base 58
|
||||
return get_account_address_as_str(nettype, false, addr, true);
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
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)
|
||||
@@ -100,6 +104,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 +140,8 @@ namespace cryptonote
|
||||
|
||||
private:
|
||||
void set_null();
|
||||
account_keys m_keys;
|
||||
protected:
|
||||
uint64_t m_creation_timestamp;
|
||||
account_keys m_keys;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -197,6 +197,23 @@ namespace cryptonote
|
||||
|
||||
};
|
||||
|
||||
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()
|
||||
};
|
||||
|
||||
class transaction_prefix
|
||||
{
|
||||
|
||||
@@ -227,6 +244,8 @@ namespace cryptonote
|
||||
// Slippage limit
|
||||
uint64_t amount_slippage_limit;
|
||||
|
||||
protocol_tx_data_t protocol_tx_data;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(version)
|
||||
if(version == 0 || CURRENT_TRANSACTION_VERSION < version) return false;
|
||||
@@ -244,8 +263,14 @@ namespace cryptonote
|
||||
FIELD(return_address_list)
|
||||
FIELD(return_address_change_mask)
|
||||
} else {
|
||||
FIELD(return_address)
|
||||
FIELD(return_pubkey)
|
||||
if (type == cryptonote::transaction_type::STAKE &&
|
||||
version >= TRANSACTION_VERSION_CARROT)
|
||||
{
|
||||
FIELD(protocol_tx_data)
|
||||
} else {
|
||||
FIELD(return_address)
|
||||
FIELD(return_pubkey)
|
||||
}
|
||||
}
|
||||
FIELD(source_asset_type)
|
||||
FIELD(destination_asset_type)
|
||||
@@ -268,6 +293,10 @@ 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 = {};
|
||||
source_asset_type.clear();
|
||||
destination_asset_type.clear();
|
||||
amount_burnt = 0;
|
||||
@@ -669,6 +698,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 +713,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 +783,7 @@ 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::transaction, 0xcc);
|
||||
VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
|
||||
|
||||
@@ -764,6 +796,7 @@ 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::transaction, "tx");
|
||||
VARIANT_TAG(json_archive, cryptonote::block, "block");
|
||||
|
||||
@@ -776,5 +809,6 @@ 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::transaction, "tx");
|
||||
VARIANT_TAG(debug_archive, cryptonote::block, "block");
|
||||
|
||||
@@ -155,9 +155,12 @@ namespace cryptonote {
|
||||
network_type nettype
|
||||
, bool subaddress
|
||||
, account_public_address const & adr
|
||||
, bool is_carrot
|
||||
)
|
||||
{
|
||||
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 = 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));
|
||||
}
|
||||
@@ -166,9 +169,10 @@ namespace cryptonote {
|
||||
network_type nettype
|
||||
, account_public_address const & adr
|
||||
, crypto::hash8 const & payment_id
|
||||
, bool is_carrot
|
||||
)
|
||||
{
|
||||
uint64_t integrated_address_prefix = get_config(nettype).CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
|
||||
uint64_t integrated_address_prefix = 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 +200,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 +218,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 +285,8 @@ namespace cryptonote {
|
||||
LOG_PRINT_L1("Failed to validate address keys");
|
||||
return false;
|
||||
}
|
||||
|
||||
info.address.m_is_carrot = info.is_carrot;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -285,8 +318,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;
|
||||
};
|
||||
|
||||
@@ -87,12 +88,14 @@ namespace cryptonote {
|
||||
network_type nettype
|
||||
, bool subaddress
|
||||
, const account_public_address& adr
|
||||
, bool is_carrot = false
|
||||
);
|
||||
|
||||
std::string get_account_integrated_address_as_str(
|
||||
network_type nettype
|
||||
, const account_public_address& adr
|
||||
, const crypto::hash8& payment_id
|
||||
, bool is_carrot = false
|
||||
);
|
||||
|
||||
bool get_account_address_from_str(
|
||||
|
||||
@@ -166,6 +166,15 @@ 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::transaction_prefix &x, const boost::serialization::version_type ver)
|
||||
@@ -183,8 +192,14 @@ 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.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;
|
||||
@@ -209,8 +224,14 @@ 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.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;
|
||||
|
||||
@@ -113,7 +113,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 +646,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");
|
||||
|
||||
@@ -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),
|
||||
@@ -176,6 +178,8 @@ namespace cryptonote
|
||||
if(!m_phandler->get_block_template(bl, m_mine_address, di, height, expected_reward, extra_nonce, seed_height, seed_hash))
|
||||
{
|
||||
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 +189,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 +407,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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
+81
-59
@@ -44,9 +44,10 @@
|
||||
#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 4
|
||||
#define TRANSACTION_VERSION_2_OUTS 2
|
||||
#define TRANSACTION_VERSION_N_OUTS 3
|
||||
#define TRANSACTION_VERSION_CARROT 4
|
||||
#define CURRENT_BLOCK_MAJOR_VERSION 1
|
||||
#define CURRENT_BLOCK_MINOR_VERSION 1
|
||||
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
|
||||
@@ -292,6 +293,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;
|
||||
@@ -313,24 +317,24 @@ namespace config
|
||||
|
||||
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, vie_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"}},
|
||||
};
|
||||
|
||||
// Hash domain separators
|
||||
@@ -396,6 +400,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;
|
||||
@@ -422,24 +429,24 @@ namespace config
|
||||
|
||||
std::string const TREASURY_ADDRESS = "SaLvTyLFta9BiAXeUfFkKvViBkFt4ay5nEUBpWyDKewYggtsoxBbtCUVqaBjtcCDyY1euun8Giv7LLEgvztuurLo5a6Km1zskZn36";
|
||||
|
||||
// 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
|
||||
const std::map<uint64_t, std::tuple<std::string, std::string, std::string, std::string>> TREASURY_SAL1_MINT_OUTPUT_DATA = {
|
||||
{1100, {"310fe378b82e2475a87c83eef07c57d92fa0731d5c499258e774852158276968","f17c5a62efcc96710f2a173538fe5e79b190b44ab6facc01a619f0e227ac18d1","eb613855f58d093ae9d527e8ab69b46a","6c74f9"}},
|
||||
{1120, {"adb74cea72d46ebe5a45e5886189e71c493308686f076ccfc053cb9b4f55b656","b40e958589238cc48a5a7f03f1f28406a13b2f724efe831cfec43c06bb0fcb60","77a51cc3a6c3c53d631cadad72f57c1d","e5fec0"}},
|
||||
{1140, {"c5e9a67c695ddcab05b980de0c8cc7d9d5b9c09af58047843bfd7d29a038f671","6c3253bd837b899b87aedc97114feb9c10c2d255ce59b7ba5b470817a37d16df","fcf6e1907ea30dbafd510e33a37cc2dc","fa5c45"}},
|
||||
{1160, {"e95c8b7fc3d0e7e34d544e97d3b526e94f70acb7d85cb0053b3cb830e863ac38","3a5ae93e922985ea1a126ff8fd35f6cbf39fa556525e15a049765510eb1360e1","7ea6d62add9387a28f3dbed5dbac120b","c26ac2"}},
|
||||
{1180, {"9d453235a25e470df2d7ceaa8f8d4216a8939a0a93bc0c43f1b902cb461ee82d","2e990ed2de4d745389d88aa9868634ce430f09d2c0cb5ebc2ee8b9bcc23e221a","807e07241a48b97acb537241822a97b8","eb37c0"}},
|
||||
{1200, {"92dbd7da158d4bcb4f002dcc505ed4c49ac4e4782724b506a5977119c80c4869","4505a9be31c2ac6ad5faa2ea8332b85b1a3efee84d0456740d208b8188ad842a","8870c1f88de25b5443d8323759f386d9","443c65"}},
|
||||
{1220, {"1e4d5c44a112c3ac89ab2c7065bb2c8c094779b3a5d696652198f7dd05f88b77","01f56bf134652852688e30dd9559bdb5fe2edd046bed99dbea23b655d2475b89","da088fc1e1c2f2d0e348f06f2079e8ed","d7c7bf"}},
|
||||
{1240, {"91ba144c930a65996b2d7c3b296217c692225756392b580a323838e48b357452","f2d5f4f2aaa599a52c557270cbc5cde138b753a98297d975b74a7223a9b80b13","0dc3a42cb1f36768a09c316790936356","172c22"}},
|
||||
{1260, {"1d626ede8d2e34e888384655b30942a25be272a3ea58d49835265e6933a91a52","05666de1b136236f0682e128c0c3ae84578a6a4b233a578dd676e581a582fe19","c81ccf7f93e01e7872543907de8d17d0","21dd94"}},
|
||||
{1280, {"85b10b5ae72ab59281f47be4edede17b7a017dc7ddd839813e3a12c0b2a39874","d34d259e2fee2b0c977242c473cf83997920c1e64ff7a9c364b2bf4abba4d5cc","43de6ce100ca3eeb6734fc44cc9f7dbc","574e2f"}},
|
||||
{1300, {"c699ca0dcbe538e6be9e997acb50a4c13557d1e8cf3a105ab47406cb68300656","50c5e0fa60907c2c2b66748562193b7f5bfcba269eb398c5c975c9e125933942","05aeb41f8863152a7e0e36f216ecbb12","e413dd"}},
|
||||
{1320, {"76bb126d6e0e5d3d7ee7ccabd194a248cbe006ae7d57f89c31c6826f8e7b4851","e1f2277b378630d92bc03003e3d206899404afde342fcb3a9b1790f798c8b5a4","26274ad1bbf5d483f2c747754b898873","a2df70"}},
|
||||
{1340, {"5738dc94686bfffe1789b695785f270f6f616b1a52e071e975cf915063233b1a","982b4848ed74f2a5d899f778b182c35f40535579349435b466ff98c3fce678e7","67bd9b9a434b9028564a065a30ae34fa","36ceec"}},
|
||||
{1360, {"473b6f6941d6eafaef007d3d932763b6e39c1428d3ba76dfff452ddc67f93b48","76e3b1280b959672d86c357e6f5fcd8a74e61a0a948a0541a0eb384060705bac","74b5ad8847471e3d8723ad3e101b8a13","5e5671"}},
|
||||
{1380, {"6dae9a14e24b96caf8f7acb0edad936a4ecaa194a61b3785a2b1d08cbca0a158","26ca204c10481ed2447447e3893e0c46c9f01df16c3f3a671cf9e6054176ee5d","7c04e4ed28bfac12a0050bdae44f9979","4c23ad"}},
|
||||
{1400, {"a5837480d8e17ddb9b29baaf5671545d59d18b546de0d7092768882cff94d125","dc76eb3892b3721da947fc71de8ab30ef32651f1b6bb1a45eb7b80882217a5ac","bb490940a3cdf4a17fd0bec0b578531f","84d899"}}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -448,6 +455,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;
|
||||
@@ -471,24 +481,24 @@ namespace config
|
||||
|
||||
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 +518,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 +533,7 @@ 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::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 +541,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 +556,15 @@ namespace cryptonote
|
||||
::config::TREASURY_SAL1_MINT_PERIOD,
|
||||
::config::AUDIT_HARD_FORKS,
|
||||
::config::TREASURY_ADDRESS,
|
||||
::config::TREASURY_SAL1_MINT_OUTPUT_KEYS
|
||||
::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 +577,15 @@ 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_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 +598,7 @@ 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_SAL1_MINT_OUTPUT_DATA
|
||||
};
|
||||
switch (nettype)
|
||||
{
|
||||
|
||||
@@ -1423,21 +1423,20 @@ bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t heigh
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
std::tuple<bool, size_t> Blockchain::validate_treasury_payout(const transaction& tx, const uint64_t payout_index, uint8_t hf_version) const {
|
||||
std::tuple<bool, size_t> Blockchain::validate_treasury_payout(const transaction& tx, const std::tuple<std::string, std::string, std::string, std::string>& treasury_data, uint8_t hf_version) const {
|
||||
|
||||
// find the treasury output
|
||||
const auto treasury_output_keys = get_config(m_nettype).TREASURY_SAL1_MINT_OUTPUT_KEYS;
|
||||
const auto expected_output_key = treasury_output_keys[payout_index].second;
|
||||
const auto &output = std::find_if(tx.vout.begin(), tx.vout.end(), [&expected_output_key](const tx_out &o) {
|
||||
const auto [tx_key, onetime_address, anchor_enc, viewtag] = treasury_data;
|
||||
const auto &oa = onetime_address; // Alias to support capture compatibility on MacOS
|
||||
const auto &output = std::find_if(tx.vout.begin(), tx.vout.end(), [&oa](const tx_out &o) {
|
||||
std::string output_key;
|
||||
if (o.target.type() == typeid(txout_to_key)) {
|
||||
output_key = epee::string_tools::pod_to_hex(boost::get<txout_to_key>(o.target).key);
|
||||
} else if (o.target.type() == typeid(txout_to_tagged_key)) {
|
||||
output_key = epee::string_tools::pod_to_hex(boost::get<txout_to_tagged_key>(o.target).key);
|
||||
if (o.target.type() == typeid(txout_to_carrot_v1)) {
|
||||
output_key = epee::string_tools::pod_to_hex(boost::get<txout_to_carrot_v1>(o.target).key);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return output_key == expected_output_key;
|
||||
return output_key == oa;
|
||||
});
|
||||
|
||||
if (output == tx.vout.end()) {
|
||||
@@ -1450,13 +1449,14 @@ std::tuple<bool, size_t> Blockchain::validate_treasury_payout(const transaction&
|
||||
return {false, 0};
|
||||
}
|
||||
|
||||
if (output->target.type() != typeid(txout_to_key)) {
|
||||
if (output->target.type() != typeid(txout_to_carrot_v1)) {
|
||||
MERROR_VER("Miner transaction contains treasury output with invalid target type");
|
||||
return {false, 0};
|
||||
}
|
||||
|
||||
if (boost::get<txout_to_key>(output->target).unlock_time != CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW) {
|
||||
MERROR_VER("Miner transaction contains treasury output with invalid target key");
|
||||
const cryptonote::txout_to_carrot_v1 target = boost::get<txout_to_carrot_v1>(output->target);
|
||||
if (target.asset_type != "SAL1") {
|
||||
MERROR_VER("Miner transaction contains treasury output with invalid asset_type");
|
||||
return {false, 0};
|
||||
}
|
||||
|
||||
@@ -1468,12 +1468,14 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
// validate treasury payout
|
||||
size_t treasury_index_in_tx_outputs;
|
||||
auto [treasury_payout_exist, treasury_payout_index] = check_treasury_payout(m_nettype, boost::get<txin_gen>(b.miner_tx.vin[0]).height, m_hardfork->get_hardforks(), version);
|
||||
if (treasury_payout_exist) {
|
||||
// check for treasury payouts
|
||||
const uint64_t height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
|
||||
const auto treasury_payout_data = get_config(m_nettype).TREASURY_SAL1_MINT_OUTPUT_DATA;
|
||||
const bool treasury_payout_exists = (treasury_payout_data.count(height) == 1);
|
||||
size_t treasury_index_in_tx_outputs = 0;
|
||||
if (treasury_payout_exists) {
|
||||
// check the treasury payout
|
||||
auto [valid, index_in_tx_outputs] = validate_treasury_payout(b.miner_tx, treasury_payout_index, version);
|
||||
auto [valid, index_in_tx_outputs] = validate_treasury_payout(b.miner_tx, treasury_payout_data.at(height), version);
|
||||
if (!valid) {
|
||||
MERROR_VER("Miner transaction treasury output was invalid");
|
||||
return false;
|
||||
@@ -1486,7 +1488,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
|
||||
for(size_t i = 0; i < b.miner_tx.vout.size(); i++)
|
||||
{
|
||||
// skip the treasury output
|
||||
if (treasury_payout_exist && (i == treasury_index_in_tx_outputs)) {
|
||||
if (treasury_payout_exists && (i == treasury_index_in_tx_outputs)) {
|
||||
continue;
|
||||
}
|
||||
money_in_use += b.miner_tx.vout[i].amount;
|
||||
@@ -1561,6 +1563,7 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
// Get the staking data for the block that matured this time
|
||||
cryptonote::yield_block_info ybi_matured;
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> yield_payouts;
|
||||
std::vector<std::pair<yield_tx_info_carrot, uint64_t>> carrot_yield_payouts;
|
||||
uint64_t matured_height = height - stake_lock_period - 1;
|
||||
bool ok = get_ybi_entry(matured_height, ybi_matured);
|
||||
if (!ok) {
|
||||
@@ -1569,10 +1572,17 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
} else if (ybi_matured.locked_coins_this_block == 0) {
|
||||
LOG_PRINT_L1("Block at height: " << height << " - no yield payouts due - skipping");
|
||||
} else {
|
||||
// Iterate over the cached data for block yield, calculating the yield payouts due
|
||||
if (!calculate_yield_payouts(matured_height, yield_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain yield payout information - aborting");
|
||||
return false;
|
||||
// Iterate over the cached data for block yield, calculating the yield payouts due
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
if (!calculate_yield_payouts(matured_height, carrot_yield_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain carrot yield payout information - aborting");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!calculate_yield_payouts(matured_height, yield_payouts)) {
|
||||
LOG_ERROR("Block at height: " << height << " - Failed to obtain yield payout information - aborting");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1605,7 +1615,36 @@ bool Blockchain::validate_protocol_transaction(const block& b, uint64_t height,
|
||||
}
|
||||
|
||||
// Check we have the correct number of entries
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vout.size() == yield_payouts.size() + audit_payouts.size(), false, "Invalid number of outputs in protocol_tx - aborting");
|
||||
CHECK_AND_ASSERT_MES(
|
||||
b.protocol_tx.vout.size() == yield_payouts.size() + audit_payouts.size() + carrot_yield_payouts.size(),
|
||||
false, "Invalid number of outputs in protocol_tx - aborting"
|
||||
);
|
||||
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
// TODO: add other verifications for carrot yield payouts
|
||||
size_t output_idx = 0;
|
||||
for (auto it = carrot_yield_payouts.begin(); it != carrot_yield_payouts.end(); it++, output_idx++) {
|
||||
// Verify the output key
|
||||
crypto::public_key out_key;
|
||||
cryptonote::get_output_public_key(b.protocol_tx.vout[output_idx], out_key);
|
||||
CHECK_AND_ASSERT_MES(out_key == it->first.return_address, false, "Incorrect output key detected in protocol_tx");
|
||||
|
||||
// Verify the output amount
|
||||
uint64_t expected_amount = it->second;
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vout[output_idx].amount == expected_amount, false, "Incorrect output amount detected in protocol_tx. expected_amount: " << expected_amount);
|
||||
|
||||
// Verify the output asset type
|
||||
std::string out_asset_type;
|
||||
cryptonote::get_output_asset_type(b.protocol_tx.vout[output_idx], out_asset_type);
|
||||
uint8_t hf_yield = m_hardfork->get_ideal_version(it->first.block_height);
|
||||
if (hf_yield >= HF_VERSION_SALVIUM_ONE_PROOFS)
|
||||
CHECK_AND_ASSERT_MES(out_asset_type == "SAL1", false, "Incorrect output asset_type (!= SAL1) detected in protocol_tx");
|
||||
else
|
||||
CHECK_AND_ASSERT_MES(out_asset_type == "SAL", false, "Incorrect output asset_type (!= SAL) detected in protocol_tx");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Merge the yield and audit payouts into an iterable vector
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> payouts{yield_payouts};
|
||||
@@ -1864,6 +1903,15 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
b.timestamp = median_ts;
|
||||
}
|
||||
|
||||
// Verify that we aren't mixing Carrot and non-Carrot
|
||||
if (b.major_version >= HF_VERSION_CARROT && !miner_address.m_is_carrot) {
|
||||
LOG_ERROR("mining to CryptoNote wallet address, but Carrot wallet address is required");
|
||||
return false;
|
||||
} else if (b.major_version < HF_VERSION_CARROT && miner_address.m_is_carrot) {
|
||||
LOG_ERROR("mining to Carrot wallet address, but Carrot isn't supported yet");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::map<std::string, uint64_t> circ_supply = get_db().get_circulating_supply();
|
||||
|
||||
// Check if we are supposed to be obtaining PRs from the Oracle
|
||||
@@ -1906,33 +1954,64 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
|
||||
|
||||
// Iterate over the cached data for block yield, calculating the yield payouts due
|
||||
std::vector<std::pair<yield_tx_info, uint64_t>> yield_payouts;
|
||||
if (!calculate_yield_payouts(start_height, yield_payouts)) {
|
||||
LOG_ERROR("Failed to obtain yield payout information - aborting");
|
||||
return false;
|
||||
std::vector<std::pair<yield_tx_info_carrot, uint64_t>> carrot_yield_payouts;
|
||||
if (b.major_version >= HF_VERSION_CARROT) {
|
||||
if (!calculate_yield_payouts(start_height, carrot_yield_payouts)) {
|
||||
LOG_ERROR("Failed to obtain yield payout information - aborting");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!calculate_yield_payouts(start_height, yield_payouts)) {
|
||||
LOG_ERROR("Failed to obtain yield payout information - aborting");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Work out what the asset_type should be based on height of submission
|
||||
uint8_t hf_submitted = m_hardfork->get_ideal_version(start_height);
|
||||
|
||||
// Create the protocol_metadata entries here
|
||||
for (const auto& yield_entry: yield_payouts) {
|
||||
cryptonote::protocol_data_entry entry;
|
||||
entry.amount_burnt = yield_entry.second;
|
||||
entry.amount_minted = 0;
|
||||
entry.amount_slippage_limit = 0;
|
||||
if (hf_submitted >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
entry.source_asset = "SAL1";
|
||||
entry.destination_asset = "SAL1";
|
||||
} else {
|
||||
entry.source_asset = "SAL";
|
||||
entry.destination_asset = "SAL";
|
||||
if (b.major_version >= HF_VERSION_CARROT) {
|
||||
for (const auto& yield_entry: carrot_yield_payouts) {
|
||||
cryptonote::protocol_data_entry entry;
|
||||
entry.amount_burnt = yield_entry.second;
|
||||
entry.amount_minted = 0;
|
||||
entry.amount_slippage_limit = 0;
|
||||
if (hf_submitted >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
entry.source_asset = "SAL1";
|
||||
entry.destination_asset = "SAL1";
|
||||
} else {
|
||||
entry.source_asset = "SAL";
|
||||
entry.destination_asset = "SAL";
|
||||
}
|
||||
entry.return_address = yield_entry.first.return_address;
|
||||
entry.type = cryptonote::transaction_type::STAKE;
|
||||
entry.return_pubkey = yield_entry.first.return_pubkey;
|
||||
entry.origin_height = start_height;
|
||||
entry.return_view_tag = yield_entry.first.return_view_tag;
|
||||
entry.return_anchor_enc = yield_entry.first.return_anchor_enc;
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
} else {
|
||||
for (const auto& yield_entry: yield_payouts) {
|
||||
cryptonote::protocol_data_entry entry;
|
||||
entry.amount_burnt = yield_entry.second;
|
||||
entry.amount_minted = 0;
|
||||
entry.amount_slippage_limit = 0;
|
||||
if (hf_submitted >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
entry.source_asset = "SAL1";
|
||||
entry.destination_asset = "SAL1";
|
||||
} else {
|
||||
entry.source_asset = "SAL";
|
||||
entry.destination_asset = "SAL";
|
||||
}
|
||||
entry.return_address = yield_entry.first.return_address;
|
||||
entry.type = cryptonote::transaction_type::STAKE;
|
||||
entry.P_change = yield_entry.first.P_change;
|
||||
entry.return_pubkey = yield_entry.first.return_pubkey;
|
||||
entry.origin_height = start_height;
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
entry.return_address = yield_entry.first.return_address;
|
||||
entry.type = cryptonote::transaction_type::STAKE;
|
||||
entry.P_change = yield_entry.first.P_change;
|
||||
entry.return_pubkey = yield_entry.first.return_pubkey;
|
||||
entry.origin_height = start_height;
|
||||
protocol_entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2353,7 +2432,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
|
||||
|
||||
if(!prevalidate_protocol_transaction(b, bei.height, hf_version))
|
||||
{
|
||||
MERROR_VER("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative) has incorrect miner transaction.");
|
||||
MERROR_VER("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative) has incorrect protocol transaction.");
|
||||
bvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
@@ -3605,10 +3684,25 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
}
|
||||
*/
|
||||
|
||||
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
// for v5, force the audit and the new SalviumOne RCT data
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
// from v11, force the new SalviumOne RCT data
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
if (tx.rct_signatures.type != rct::RCTTypeSalviumOne) {
|
||||
MERROR_VER("SalviumOne data required after v" + std::to_string(HF_VERSION_CARROT));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (tx.rct_signatures.type != rct::RCTTypeNull) {
|
||||
MERROR_VER("NULL RCT required for coinbase TXs after v" + std::to_string(HF_VERSION_CARROT));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
// for v5, force the audit and the new SalviumZero RCT data
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
if (tx.rct_signatures.type != rct::RCTTypeSalviumZero) {
|
||||
MERROR_VER("FullProofs plus Audit data required after v" + std::to_string(HF_VERSION_SALVIUM_ONE_PROOFS));
|
||||
tvc.m_invalid_output = true;
|
||||
return false;
|
||||
@@ -3674,7 +3768,7 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
|
||||
}
|
||||
|
||||
// After v2 allow N-out TXs for TRANSFER ONLY
|
||||
if (hf_version >= HF_VERSION_ENABLE_N_OUTS) {
|
||||
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && hf_version < HF_VERSION_CARROT) {
|
||||
if (tx.version >= TRANSACTION_VERSION_N_OUTS && tx.type != cryptonote::transaction_type::TRANSFER) {
|
||||
MERROR("N-out TXs are only permitted for TRANSFER TX type");
|
||||
tvc.m_version_mismatch = true;
|
||||
@@ -3682,6 +3776,14 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
|
||||
}
|
||||
}
|
||||
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
if (tx.version != TRANSACTION_VERSION_CARROT) {
|
||||
MERROR("TX version " + std::to_string(tx.version) + " is not supported, expected " + std::to_string(TRANSACTION_VERSION_CARROT));
|
||||
tvc.m_version_mismatch = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure CONVERT TXs are disabled until we are ready - belt and braces!
|
||||
if (hf_version < HF_VERSION_ENABLE_CONVERT) {
|
||||
if (tx.type == cryptonote::transaction_type::CONVERT) {
|
||||
@@ -3725,7 +3827,7 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const
|
||||
bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys, const uint8_t &hf_version)
|
||||
{
|
||||
PERF_TIMER(expand_transaction_2);
|
||||
CHECK_AND_ASSERT_MES(tx.version == 2 || tx.version == 3, false, "Transaction version is not 2/3");
|
||||
CHECK_AND_ASSERT_MES(tx.version == 2 || tx.version == 3 || tx.version == 4, false, "Transaction version is not 2/3/4");
|
||||
|
||||
rct::rctSig &rv = tx.rct_signatures;
|
||||
|
||||
@@ -3748,7 +3850,7 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne)
|
||||
else if (rv.type == rct::RCTTypeSimple || rv.type == rct::RCTTypeBulletproof || rv.type == rct::RCTTypeBulletproof2 || rv.type == rct::RCTTypeCLSAG || rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumZero || rv.type == rct::RCTTypeSalviumOne)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!pubkeys.empty() && !pubkeys[0].empty(), false, "empty pubkeys");
|
||||
rv.mixRing.resize(pubkeys.size());
|
||||
@@ -3924,14 +4026,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
return false;
|
||||
}
|
||||
|
||||
// min/max tx version based on HF, and we accept v1 txes if having a non mixable
|
||||
const size_t max_tx_version = (hf_version >= HF_VERSION_ENABLE_N_OUTS) ? TRANSACTION_VERSION_N_OUTS : TRANSACTION_VERSION_2_OUTS;
|
||||
if (tx.version > max_tx_version)
|
||||
{
|
||||
MERROR_VER("transaction version " << (unsigned)tx.version << " is higher than max accepted version " << max_tx_version);
|
||||
tvc.m_verifivation_failed = true;
|
||||
return false;
|
||||
}
|
||||
const size_t min_tx_version = (n_unmixable > 0 ? 1 : 2);
|
||||
if (tx.version < min_tx_version)
|
||||
{
|
||||
@@ -4098,8 +4192,13 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
const rct::rctSig &rv = tx.rct_signatures;
|
||||
|
||||
// Check that after full proofs are enabled, the RCT version is set to enforce full proofs
|
||||
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("Unsupported rct type (Salvium One / SPARC proofs are required): " << rv.type);
|
||||
return false;
|
||||
}
|
||||
} else if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
|
||||
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumZero) {
|
||||
MERROR_VER("Unsupported rct type (full proofs (with audit data) are required): " << rv.type);
|
||||
return false;
|
||||
}
|
||||
@@ -4123,6 +4222,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
|
||||
case rct::RCTTypeCLSAG:
|
||||
case rct::RCTTypeBulletproofPlus:
|
||||
case rct::RCTTypeFullProofs:
|
||||
case rct::RCTTypeSalviumZero:
|
||||
case rct::RCTTypeSalviumOne:
|
||||
{
|
||||
if (!ver_rct_non_semantics_simple_cached(tx, pubkeys, m_rct_ver_cache, RCT_CACHE_TYPE, hf_version))
|
||||
@@ -4559,6 +4659,68 @@ bool Blockchain::get_abi_entry(const uint64_t height, cryptonote::audit_block_in
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info_carrot, uint64_t>>& yield_container)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
// Clear the yield payout amounts
|
||||
yield_container.clear();
|
||||
|
||||
// Get the YIELD TX information for matured staked coins
|
||||
std::vector<cryptonote::yield_tx_info_carrot> yield_entries;
|
||||
// We get the yield_tx_info from the block _before_ they started to accrue yield
|
||||
int yield_tx_result = m_db->get_carrot_yield_tx_info(start_height, yield_entries);
|
||||
if (!yield_entries.size()) {
|
||||
|
||||
// Report error and abort
|
||||
LOG_ERROR("calculate_yield_payouts() called, but no yield TXs found at height " << start_height << " - aborting");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build a blacklist of staking TXs _not_ to pay out for
|
||||
const std::set<std::string> txs_blacklist = {};
|
||||
|
||||
// Get the YBI information for the 21,600 blocks that the matured TX(s), we can calculate yield
|
||||
for (const auto& entry: yield_entries) {
|
||||
// Check to see if this entry is in the blacklist
|
||||
if (txs_blacklist.find(epee::string_tools::pod_to_hex(entry.tx_hash)) != txs_blacklist.end()) {
|
||||
LOG_ERROR("calculate_yield_payouts() found blacklisted TX at height " << start_height << " - skipping payout");
|
||||
continue;
|
||||
}
|
||||
yield_container.emplace_back(std::make_pair(entry, entry.locked_coins));
|
||||
}
|
||||
|
||||
// Iterate over the cached yield_block_info data
|
||||
uint64_t yield_lock_period = cryptonote::get_config(m_nettype).STAKE_LOCK_PERIOD;
|
||||
for (uint64_t idx = start_height+1; idx <= start_height + yield_lock_period; ++idx) {
|
||||
// Get the next block
|
||||
if (m_yield_block_info_cache.count(idx) == 0) {
|
||||
LOG_ERROR("failed to locate yield information for block height " << idx <<" - aborting");
|
||||
return false;
|
||||
}
|
||||
yield_block_info ybi = m_yield_block_info_cache[idx];
|
||||
if (ybi.slippage_total_this_block == 0) continue;
|
||||
if (ybi.locked_coins_tally == 0) continue;
|
||||
|
||||
boost::multiprecision::int128_t slippage_128 = ybi.slippage_total_this_block;
|
||||
|
||||
// Get the total number of coins locked at this height
|
||||
boost::multiprecision::int128_t locked_total_128 = ybi.locked_coins_tally;
|
||||
|
||||
// Iterate over the yield_container, adding each proportion of the yield
|
||||
for (auto& entry: yield_container) {
|
||||
|
||||
boost::multiprecision::int128_t locked_coins_128 = entry.first.locked_coins;
|
||||
boost::multiprecision::int128_t yield_128 = (slippage_128 * locked_coins_128) / locked_total_128;
|
||||
entry.second += yield_128.convert_to<uint64_t>();
|
||||
}
|
||||
}
|
||||
|
||||
// Return success to caller
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------
|
||||
//------------------------------------------------------------------
|
||||
bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_container)
|
||||
{
|
||||
LOG_PRINT_L3("Blockchain::" << __func__);
|
||||
|
||||
@@ -1175,6 +1175,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
|
||||
*
|
||||
@@ -1500,7 +1507,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
|
||||
|
||||
@@ -843,7 +843,9 @@ 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_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
|
||||
@@ -924,7 +926,7 @@ namespace cryptonote
|
||||
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 +934,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");
|
||||
@@ -990,6 +1000,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))
|
||||
{
|
||||
@@ -1017,7 +1028,7 @@ namespace cryptonote
|
||||
{
|
||||
if (!tx_info[n].result)
|
||||
continue;
|
||||
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && 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;
|
||||
if (!rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures,
|
||||
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
|
||||
|
||||
@@ -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,
|
||||
@@ -390,29 +362,15 @@ 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;
|
||||
e.amount = 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);
|
||||
}
|
||||
|
||||
@@ -476,7 +434,8 @@ namespace cryptonote
|
||||
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 +455,61 @@ namespace cryptonote
|
||||
{
|
||||
try
|
||||
{
|
||||
// Build the miner payout
|
||||
carrot::CarrotDestinationV1 destination;
|
||||
carrot::make_carrot_main_address_v1(miner_address.m_spend_public_key,
|
||||
miner_address.m_view_public_key,
|
||||
destination);
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(!destination.is_subaddress,
|
||||
"make_single_enote_carrot_coinbase_transaction_v1: subaddress are not allowed in miner transactions");
|
||||
CHECK_AND_ASSERT_THROW_MES(destination.payment_id == carrot::null_payment_id,
|
||||
"make_single_enote_carrot_coinbase_transaction_v1: 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 carrot::CarrotPaymentProposalV1 payment_proposal{
|
||||
.destination = destination,
|
||||
.amount = block_reward - stake_reward,
|
||||
.asset_type = "SAL1",
|
||||
.randomness = carrot::gen_janus_anchor()
|
||||
};
|
||||
|
||||
std::vector<carrot::CarrotCoinbaseEnoteV1> enotes(treasury_payout_exists ? 2 : 1);
|
||||
carrot::get_coinbase_output_proposal_v1(payment_proposal, height, enotes.front());
|
||||
|
||||
// Check to see if there needs to be a treasury payout
|
||||
if (treasury_payout_exists) {
|
||||
|
||||
// Convert the strings into meaningful data
|
||||
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");
|
||||
|
||||
// Manually produce an enote for the treasury payout using the hardcoded keys
|
||||
carrot::CarrotCoinbaseEnoteV1 &treasury_enote = enotes.back();
|
||||
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
|
||||
if (enotes[0].onetime_address > enotes[1].onetime_address) {
|
||||
std::swap(enotes[0], enotes[1]);
|
||||
}
|
||||
}
|
||||
|
||||
tx = carrot::store_carrot_to_coinbase_transaction_v1(enotes, extra_nonce, cryptonote::transaction_type::MINER, height);
|
||||
|
||||
tx.amount_burnt = stake_reward;
|
||||
tx.invalidate_hashes();
|
||||
}
|
||||
@@ -573,7 +580,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 +593,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,6 +68,8 @@ 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;
|
||||
};
|
||||
|
||||
@@ -75,8 +77,6 @@ namespace cryptonote
|
||||
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);
|
||||
//---------------------------------------------------------------
|
||||
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);
|
||||
|
||||
struct tx_source_entry
|
||||
{
|
||||
|
||||
@@ -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 > 4 || 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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1352,10 +1352,10 @@ 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);
|
||||
req.miner_address = cryptonote::get_account_address_as_str(nettype, false, address, is_carrot);
|
||||
req.threads_count = num_threads;
|
||||
req.do_background_mining = do_background_mining;
|
||||
req.ignore_battery = ignore_battery;
|
||||
@@ -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();
|
||||
|
||||
@@ -1930,7 +1930,7 @@ namespace hw {
|
||||
|
||||
// ====== Aout, Bout, AKout, C, v, k ======
|
||||
kv_offset = data_offset;
|
||||
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs) {
|
||||
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs || type==rct::RCTTypeSalviumZero || type==rct::RCTTypeSalviumOne) {
|
||||
C_offset = kv_offset+ (8)*outputs_size;
|
||||
} else {
|
||||
C_offset = kv_offset+ (32+32)*outputs_size;
|
||||
@@ -1947,7 +1947,7 @@ namespace hw {
|
||||
offset = set_command_header(INS_VALIDATE, 0x02, i+1);
|
||||
//options
|
||||
this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
|
||||
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs)?0x02:0x00;
|
||||
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs || type==rct::RCTTypeSalviumZero || type==rct::RCTTypeSalviumOne)?0x02:0x00;
|
||||
offset += 1;
|
||||
//is_subaddress
|
||||
this->buffer_send[offset] = outKeys.is_subaddress;
|
||||
@@ -1968,7 +1968,7 @@ namespace hw {
|
||||
memmove(this->buffer_send+offset, data+C_offset,32);
|
||||
offset += 32;
|
||||
C_offset += 32;
|
||||
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs) {
|
||||
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs || type==rct::RCTTypeSalviumZero || type==rct::RCTTypeSalviumOne) {
|
||||
//k
|
||||
memset(this->buffer_send+offset, 0, 32);
|
||||
offset += 32;
|
||||
|
||||
@@ -857,6 +857,8 @@ static bool set_tx_rct_signatures(
|
||||
rv.type = rct::RCTTypeBulletproofPlus;
|
||||
else if (rct_config.bp_version == 5)
|
||||
rv.type = rct::RCTTypeFullProofs;
|
||||
else if (rct_config.bp_version == 6)
|
||||
rv.type = rct::RCTTypeSalviumZero;
|
||||
else
|
||||
return false;
|
||||
rv.txnFee = fee;
|
||||
@@ -934,7 +936,7 @@ static bool set_tx_rct_signatures(
|
||||
}
|
||||
sc_sub(difference.bytes, sumpouts.bytes, sumouts.bytes);
|
||||
rct::genC(rv.p_r, difference, 0);
|
||||
if (rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne) {
|
||||
if (rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumZero || rv.type == rct::RCTTypeSalviumOne) {
|
||||
rv.salvium_data.pr_proof = rct::PRProof_Gen(difference);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(rct::PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), "PRProof_Ver() failed on recently created proof");
|
||||
@@ -954,7 +956,7 @@ static bool set_tx_rct_signatures(
|
||||
// check balance if reconstructing the tx
|
||||
else {
|
||||
rv.p.pseudoOuts = unsigned_tx.rct_signatures.p.pseudoOuts;
|
||||
if (rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumOne) {
|
||||
if (rv.type == rct::RCTTypeFullProofs || rv.type == rct::RCTTypeSalviumZero || rv.type == rct::RCTTypeSalviumOne) {
|
||||
if (!rct::PRProof_Ver(unsigned_tx.rct_signatures.p_r, unsigned_tx.rct_signatures.salvium_data.pr_proof))
|
||||
return false;
|
||||
rv.p_r = unsigned_tx.rct_signatures.p_r;
|
||||
|
||||
@@ -1579,7 +1579,7 @@ namespace rct {
|
||||
DP(rv.p_r);
|
||||
|
||||
// set salvium_data
|
||||
if (rv.type == RCTTypeFullProofs || rv.type == RCTTypeSalviumZero || rv.type == RCTTypeSalviumOne) {
|
||||
if (rv.type == RCTTypeSalviumOne) {
|
||||
rv.salvium_data.pr_proof = PRProof_Gen(difference);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(PRProof_Ver(rv.p_r, rv.salvium_data.pr_proof), "PRProof_Ver() failed on recently created proof");
|
||||
@@ -1611,8 +1611,12 @@ namespace rct {
|
||||
{
|
||||
if (hwdev.get_mode() == hw::device::TRANSACTION_CREATE_FAKE)
|
||||
rv.p.TCLSAGs[i] = make_dummy_tclsag(rv.mixRing[i].size());
|
||||
else
|
||||
else {
|
||||
rv.p.TCLSAGs[i] = proveRctTCLSAGSimple(full_message, rv.mixRing[i], inSk[i].x, inSk[i].y, inSk[i].mask, a[i], pseudoOuts[i], index[i], hwdev);
|
||||
#ifdef DBG
|
||||
CHECK_AND_ASSERT_THROW_MES(verRctTCLSAGSimple(full_message, rv.p.TCLSAGs[i], rv.mixRing[i], pseudoOuts[i]), "T-CLSAG verification failed");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -446,7 +446,7 @@ namespace rct {
|
||||
return false;
|
||||
for (size_t i = 0; i < outputs; ++i)
|
||||
{
|
||||
if (type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero)
|
||||
if (type == RCTTypeBulletproofPlus || type == RCTTypeFullProofs || type == RCTTypeSalviumZero || type == RCTTypeSalviumOne)
|
||||
{
|
||||
// Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
|
||||
// first 8 bytes of ecdhInfo[i].amount
|
||||
@@ -504,7 +504,7 @@ namespace rct {
|
||||
FIELD(outPk)
|
||||
VARINT_FIELD(txnFee)
|
||||
FIELD(p_r)
|
||||
if (type == RCTTypeSalviumZero)
|
||||
if (type == RCTTypeSalviumZero || type == RCTTypeSalviumOne)
|
||||
{
|
||||
FIELD(salvium_data)
|
||||
}
|
||||
@@ -673,6 +673,7 @@ namespace rct {
|
||||
FIELD(bulletproofs_plus)
|
||||
FIELD(MGs)
|
||||
FIELD(CLSAGs)
|
||||
FIELD(TCLSAGs)
|
||||
FIELD(pseudoOuts)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
@@ -1432,7 +1432,7 @@ namespace cryptonote
|
||||
RPC_TRACKER(start_mining);
|
||||
CHECK_CORE_READY();
|
||||
cryptonote::address_parse_info info;
|
||||
if(!get_account_address_from_str(info, nettype(), req.miner_address))
|
||||
if(!get_account_address_from_str(info, m_core.get_nettype(), req.miner_address))
|
||||
{
|
||||
res.status = "Failed, wrong address";
|
||||
LOG_PRINT_L0(res.status);
|
||||
@@ -1445,6 +1445,17 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint8_t version = m_core.get_blockchain_storage().get_current_hard_fork_version();
|
||||
if (info.is_carrot && version < HF_VERSION_CARROT) {
|
||||
res.status = "Mining to Carrot wallet address, but Carrot isn't supported yet";
|
||||
LOG_PRINT_L0(res.status);
|
||||
return true;
|
||||
} else if (!info.is_carrot && version >= HF_VERSION_CARROT) {
|
||||
res.status = "Mining to CryptoNote wallet address, but Carrot wallet address is required";
|
||||
LOG_PRINT_L0(res.status);
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int concurrency_count = boost::thread::hardware_concurrency() * 4;
|
||||
|
||||
// if we couldn't detect threads, set it to a ridiculously high number
|
||||
@@ -1958,6 +1969,17 @@ namespace cryptonote
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t version = m_core.get_blockchain_storage().get_current_hard_fork_version();
|
||||
if (info.is_carrot && version < HF_VERSION_CARROT) {
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INVALID_CLIENT;
|
||||
error_resp.message = "Mining to Carrot wallet address, but Carrot isn't supported yet";
|
||||
return false;
|
||||
} else if (!info.is_carrot && version >= HF_VERSION_CARROT) {
|
||||
error_resp.code = CORE_RPC_ERROR_CODE_INVALID_CLIENT;
|
||||
error_resp.message = "Mining to CryptoNote wallet address, but Carrot wallet address is required";
|
||||
return false;
|
||||
}
|
||||
|
||||
block b;
|
||||
cryptonote::blobdata blob_reserve;
|
||||
size_t reserved_offset;
|
||||
|
||||
@@ -277,8 +277,14 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::t
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_address_list, tx.return_address_list);
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_address_change_mask, tx.return_address_change_mask);
|
||||
} else {
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_address, tx.return_address);
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_pubkey, tx.return_pubkey);
|
||||
if (tx.type == cryptonote::transaction_type::STAKE &&
|
||||
tx.version >= TRANSACTION_VERSION_CARROT)
|
||||
{
|
||||
INSERT_INTO_JSON_OBJECT(dest, protocol_tx_data, tx.protocol_tx_data);
|
||||
} else {
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_address, tx.return_address);
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_pubkey, tx.return_pubkey);
|
||||
}
|
||||
}
|
||||
INSERT_INTO_JSON_OBJECT(dest, source_asset_type, tx.source_asset_type);
|
||||
INSERT_INTO_JSON_OBJECT(dest, destination_asset_type, tx.destination_asset_type);
|
||||
@@ -320,8 +326,14 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx)
|
||||
GET_FROM_JSON_OBJECT(val, tx.return_address_list, return_address_list);
|
||||
GET_FROM_JSON_OBJECT(val, tx.return_address_change_mask, return_address_change_mask);
|
||||
} else {
|
||||
GET_FROM_JSON_OBJECT(val, tx.return_address, return_address);
|
||||
GET_FROM_JSON_OBJECT(val, tx.return_pubkey, return_pubkey);
|
||||
if (tx.type == cryptonote::transaction_type::STAKE &&
|
||||
tx.version >= TRANSACTION_VERSION_CARROT)
|
||||
{
|
||||
GET_FROM_JSON_OBJECT(val, tx.protocol_tx_data, protocol_tx_data);
|
||||
} else {
|
||||
GET_FROM_JSON_OBJECT(val, tx.return_address, return_address);
|
||||
GET_FROM_JSON_OBJECT(val, tx.return_pubkey, return_pubkey);
|
||||
}
|
||||
}
|
||||
GET_FROM_JSON_OBJECT(val, tx.source_asset_type, source_asset_type);
|
||||
GET_FROM_JSON_OBJECT(val, tx.destination_asset_type, destination_asset_type);
|
||||
@@ -506,6 +518,33 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash&
|
||||
}
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::protocol_tx_data_t& ptd)
|
||||
{
|
||||
dest.StartObject();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(dest, version, ptd.version);
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_address, ptd.return_address);
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_pubkey, ptd.return_pubkey);
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_view_tag, ptd.return_view_tag);
|
||||
INSERT_INTO_JSON_OBJECT(dest, return_anchor_enc, ptd.return_anchor_enc);
|
||||
|
||||
dest.EndObject();
|
||||
}
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::protocol_tx_data_t& ptd)
|
||||
{
|
||||
if (!val.IsObject())
|
||||
{
|
||||
throw WRONG_TYPE("json object");
|
||||
}
|
||||
|
||||
GET_FROM_JSON_OBJECT(val, ptd.version, version);
|
||||
GET_FROM_JSON_OBJECT(val, ptd.return_address, return_address);
|
||||
GET_FROM_JSON_OBJECT(val, ptd.return_pubkey, return_pubkey);
|
||||
GET_FROM_JSON_OBJECT(val, ptd.return_view_tag, return_view_tag);
|
||||
GET_FROM_JSON_OBJECT(val, ptd.return_anchor_enc, return_anchor_enc);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_key& txin)
|
||||
{
|
||||
dest.StartObject();
|
||||
@@ -1201,7 +1240,7 @@ void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const rct::rctSig&
|
||||
INSERT_INTO_JSON_OBJECT(dest, commitments, transform(sig.outPk, just_mask));
|
||||
INSERT_INTO_JSON_OBJECT(dest, fee, sig.txnFee);
|
||||
INSERT_INTO_JSON_OBJECT(dest, p_r, sig.p_r);
|
||||
if (sig.type == rct::RCTTypeSalviumOne) {
|
||||
if (sig.type == rct::RCTTypeSalviumZero || sig.type == rct::RCTTypeSalviumOne) {
|
||||
INSERT_INTO_JSON_OBJECT(dest, salvium_data, sig.salvium_data);
|
||||
} else if (sig.type == rct::RCTTypeFullProofs) {
|
||||
INSERT_INTO_JSON_OBJECT(dest, pr_proof, sig.salvium_data.pr_proof);
|
||||
@@ -1245,7 +1284,7 @@ void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig)
|
||||
GET_FROM_JSON_OBJECT(val, sig.outPk, commitments);
|
||||
GET_FROM_JSON_OBJECT(val, sig.txnFee, fee);
|
||||
GET_FROM_JSON_OBJECT(val, sig.p_r, p_r);
|
||||
if (sig.type == rct::RCTTypeSalviumOne) {
|
||||
if (sig.type == rct::RCTTypeSalviumZero || sig.type == rct::RCTTypeSalviumOne) {
|
||||
GET_FROM_JSON_OBJECT(val, sig.salvium_data, salvium_data);
|
||||
} else if (sig.type == rct::RCTTypeFullProofs) {
|
||||
GET_FROM_JSON_OBJECT(val, sig.salvium_data.pr_proof, pr_proof);
|
||||
|
||||
@@ -218,6 +218,9 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash&
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txin_to_key& txin);
|
||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_key& txin);
|
||||
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::protocol_tx_data_t& ptd);
|
||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::protocol_tx_data_t& ptd);
|
||||
|
||||
void toJsonValue(rapidjson::Writer<epee::byte_stream>& dest, const cryptonote::txout_target_v& txout);
|
||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_target_v& txout);
|
||||
|
||||
|
||||
@@ -79,6 +79,9 @@
|
||||
#include "wallet/message_store.h"
|
||||
#include "QrCode.hpp"
|
||||
|
||||
#include "carrot_impl/subaddress_index.h"
|
||||
#include "carrot_core/core_types.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <boost/locale.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -854,6 +857,40 @@ std::string simple_wallet::get_command_usage(const std::vector<std::string> &arg
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool simple_wallet::carrot_keys(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
// don't log
|
||||
PAUSE_READLINE();
|
||||
if (m_wallet->key_on_device()) {
|
||||
std::cout << "secret: On device. Not available" << std::endl;
|
||||
} else {
|
||||
SCOPED_WALLET_UNLOCK();
|
||||
printf("master secret: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().s_master);
|
||||
putchar('\n');
|
||||
printf("prove-spend key: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().k_prove_spend);
|
||||
putchar('\n');
|
||||
printf("view-balance secret: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().s_view_balance);
|
||||
putchar('\n');
|
||||
printf("generate-image key: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().k_generate_image);
|
||||
putchar('\n');
|
||||
printf("view-incoming key: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().k_view_incoming);
|
||||
putchar('\n');
|
||||
printf("generate-address secret: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().s_generate_address);
|
||||
putchar('\n');
|
||||
}
|
||||
// TODO: print the public wallet address for the different wallet tiers
|
||||
//std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_view_public_key) << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool simple_wallet::viewkey(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
|
||||
{
|
||||
// don't log
|
||||
@@ -866,7 +903,8 @@ bool simple_wallet::viewkey(const std::vector<std::string> &args/* = std::vector
|
||||
print_secret_key(m_wallet->get_account().get_keys().m_view_secret_key);
|
||||
putchar('\n');
|
||||
}
|
||||
std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_view_public_key) << std::endl;
|
||||
std::cout << "CN public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_view_public_key) << std::endl;
|
||||
std::cout << "Carrot public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_carrot_account_address.m_view_public_key) << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -889,7 +927,8 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args/* = std::vecto
|
||||
print_secret_key(m_wallet->get_account().get_keys().m_spend_secret_key);
|
||||
putchar('\n');
|
||||
}
|
||||
std::cout << "public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key) << std::endl;
|
||||
std::cout << "CN public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key) << std::endl;
|
||||
std::cout << "Carrot public: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_carrot_account_address.m_spend_public_key) << std::endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3599,6 +3638,9 @@ simple_wallet::simple_wallet()
|
||||
m_cmd_binder.set_handler("save_watch_only",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::save_watch_only, _1),
|
||||
tr("Save a watch-only keys file."));
|
||||
m_cmd_binder.set_handler("carrot_keys",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::carrot_keys, _1),
|
||||
tr("Display the Carrot private keys."));
|
||||
m_cmd_binder.set_handler("viewkey",
|
||||
boost::bind(&simple_wallet::on_command, this, &simple_wallet::viewkey, _1),
|
||||
tr("Display the private view key."));
|
||||
@@ -5196,8 +5238,17 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
|
||||
try
|
||||
{
|
||||
recovery_val = m_wallet->generate(m_wallet_file, std::move(rc.second).password(), recovery_key, recover, two_random, create_address_file);
|
||||
message_writer(console_color_white, true) << tr("Generated new wallet: ")
|
||||
message_writer(console_color_white, true) << tr("Generated new legacy (CN) wallet: ")
|
||||
<< m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
|
||||
const auto addr = m_wallet->get_account().cryptonote_address(carrot::null_payment_id, carrot::AddressDeriveType::Carrot);
|
||||
cryptonote::account_public_address carrot_address {
|
||||
.m_spend_public_key = addr.address_spend_pubkey,
|
||||
.m_view_public_key = addr.address_view_pubkey,
|
||||
.m_is_carrot = true
|
||||
};
|
||||
message_writer(console_color_white, true) << tr("Generated new Carrot wallet: ")
|
||||
<< cryptonote::get_account_address_as_str(m_wallet->nettype(), false, carrot_address, true);
|
||||
PAUSE_READLINE();
|
||||
std::cout << tr("View key: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().m_view_secret_key);
|
||||
@@ -5271,8 +5322,11 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
|
||||
{
|
||||
m_wallet->generate(m_wallet_file, std::move(rc.second).password(), address, viewkey, create_address_file);
|
||||
}
|
||||
message_writer(console_color_white, true) << tr("Generated new wallet: ")
|
||||
message_writer(console_color_white, true) << tr("Generated new legacy wallet: ")
|
||||
<< m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
|
||||
message_writer(console_color_white, true) << tr("Generated new carrot wallet: ")
|
||||
<< cryptonote::get_account_address_as_str(m_wallet->nettype(), false, m_wallet->get_account().get_keys().m_carrot_account_address);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
@@ -5431,9 +5485,13 @@ boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::p
|
||||
else if (m_wallet->is_background_wallet())
|
||||
prefix = tr("Opened background wallet");
|
||||
else
|
||||
prefix = tr("Opened wallet");
|
||||
prefix = tr("Opened legacy (CN) wallet");
|
||||
|
||||
message_writer(console_color_white, true) <<
|
||||
prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
prefix = tr("Opened Carrot wallet");
|
||||
message_writer(console_color_white, true) <<
|
||||
prefix << ": " << m_wallet->get_account().get_carrot_public_address_str(m_wallet->nettype());
|
||||
if (m_wallet->get_account().get_device()) {
|
||||
message_writer(console_color_white, true) << "Wallet is on device: " << m_wallet->get_account().get_device().get_name();
|
||||
}
|
||||
@@ -5593,7 +5651,11 @@ void simple_wallet::start_background_mining()
|
||||
{
|
||||
COMMAND_RPC_START_MINING::request req;
|
||||
COMMAND_RPC_START_MINING::response res;
|
||||
req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
uint8_t hf_version = m_wallet->get_current_hard_fork();
|
||||
if (hf_version >= HF_VERSION_CARROT)
|
||||
req.miner_address = m_wallet->get_account().get_carrot_public_address_str(m_wallet->nettype());
|
||||
else
|
||||
req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
req.threads_count = 1;
|
||||
req.do_background_mining = true;
|
||||
req.ignore_battery = false;
|
||||
@@ -5717,7 +5779,11 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args)
|
||||
return true;
|
||||
}
|
||||
COMMAND_RPC_START_MINING::request req = AUTO_VAL_INIT(req);
|
||||
req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
uint8_t hf_version = m_wallet->get_current_hard_fork();
|
||||
if (hf_version >= HF_VERSION_CARROT)
|
||||
req.miner_address = m_wallet->get_account().get_carrot_public_address_str(m_wallet->nettype());
|
||||
else
|
||||
req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||
|
||||
bool ok = true;
|
||||
size_t arg_size = args.size();
|
||||
@@ -6320,6 +6386,7 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
|
||||
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
|
||||
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
|
||||
std::vector<std::string> asset_types = m_wallet->list_asset_types();
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
for (auto& asset: asset_types) {
|
||||
uint64_t blocks_to_unlock, time_to_unlock;
|
||||
uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, asset, false, &blocks_to_unlock, &time_to_unlock);
|
||||
@@ -6343,8 +6410,10 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
|
||||
m_wallet->get_transfers(transfers);
|
||||
for (const auto& i : balance_per_subaddress)
|
||||
{
|
||||
carrot::subaddress_index_extended subaddr = {{m_current_subaddress_account, i.first},
|
||||
is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot};
|
||||
cryptonote::subaddress_index subaddr_index = {m_current_subaddress_account, i.first};
|
||||
std::string address_str = m_wallet->get_subaddress_as_str(subaddr_index).substr(0, 6);
|
||||
std::string address_str = m_wallet->get_subaddress_as_str(subaddr).substr(0, 6);
|
||||
uint64_t num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&subaddr_index](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == subaddr_index; });
|
||||
success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first].first) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
|
||||
}
|
||||
@@ -8084,7 +8153,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
|
||||
try
|
||||
{
|
||||
// figure out what tx will be necessary
|
||||
auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, outputs, fake_outs_count, 0 /* unlock_time */, priority, extra);
|
||||
auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, cryptonote::transaction_type::TRANSFER, info.is_subaddress, outputs, fake_outs_count, 0 /* unlock_time */, priority, extra);
|
||||
|
||||
if (ptx_vector.empty())
|
||||
{
|
||||
@@ -8357,8 +8426,8 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
|
||||
asset_type = td.asset_type;
|
||||
}
|
||||
std::ostringstream prompt;
|
||||
if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
|
||||
return true;
|
||||
// if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
|
||||
// return true;
|
||||
prompt << boost::format(tr("Returning %s %s for a total fee of %s %s. Is this okay?")) %
|
||||
print_money(total_sent) % asset_type %
|
||||
print_money(total_fee) % asset_type;
|
||||
@@ -8789,29 +8858,31 @@ bool simple_wallet::donate(const std::vector<std::string> &args_)
|
||||
fail_msg_writer() << tr("amount is wrong: ") << local_args.back() << ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits<uint64_t>::max());
|
||||
return true;
|
||||
}
|
||||
uint8_t hf_version = m_wallet->get_current_hard_fork();
|
||||
// push back address, amount, payment id
|
||||
std::string address_str;
|
||||
std::string DONATION_ADDR = (hf_version >= HF_VERSION_CARROT) ? SALVIUM_DONATION_ADDR_CARROT : SALVIUM_DONATION_ADDR;
|
||||
if (m_wallet->nettype() != cryptonote::MAINNET)
|
||||
{
|
||||
// if not mainnet, convert donation address string to the relevant network type
|
||||
address_parse_info info;
|
||||
if (!cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, SALVIUM_DONATION_ADDR))
|
||||
if (!cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, DONATION_ADDR))
|
||||
{
|
||||
fail_msg_writer() << tr("Failed to parse donation address: ") << SALVIUM_DONATION_ADDR;
|
||||
fail_msg_writer() << tr("Failed to parse donation address: ") << DONATION_ADDR;
|
||||
return true;
|
||||
}
|
||||
address_str = cryptonote::get_account_address_as_str(m_wallet->nettype(), info.is_subaddress, info.address);
|
||||
}
|
||||
else
|
||||
{
|
||||
address_str = SALVIUM_DONATION_ADDR;
|
||||
address_str = DONATION_ADDR;
|
||||
}
|
||||
local_args.push_back(address_str);
|
||||
local_args.push_back(amount_str);
|
||||
if (!payment_id_str.empty())
|
||||
local_args.push_back(payment_id_str);
|
||||
if (m_wallet->nettype() == cryptonote::MAINNET)
|
||||
message_writer() << (boost::format(tr("Donating %s %s to The Salvium Team (donate.salvium.io or %s).")) % amount_str % cryptonote::get_unit(cryptonote::get_default_decimal_point()) % SALVIUM_DONATION_ADDR).str();
|
||||
message_writer() << (boost::format(tr("Donating %s %s to The Salvium Team (donate.salvium.io or %s).")) % amount_str % cryptonote::get_unit(cryptonote::get_default_decimal_point()) % DONATION_ADDR).str();
|
||||
else
|
||||
message_writer() << (boost::format(tr("Donating %s %s to %s.")) % amount_str % cryptonote::get_unit(cryptonote::get_default_decimal_point()) % address_str).str();
|
||||
transfer(local_args);
|
||||
@@ -10749,15 +10820,16 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
|
||||
std::vector<std::string> local_args = args;
|
||||
tools::wallet2::transfer_container transfers;
|
||||
m_wallet->get_transfers(transfers);
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
|
||||
auto print_address_sub = [this, &transfers](uint32_t index)
|
||||
auto print_address_sub = [this, &transfers, is_carrot](uint32_t index)
|
||||
{
|
||||
bool used = std::find_if(
|
||||
transfers.begin(), transfers.end(),
|
||||
[this, &index](const tools::wallet2::transfer_details& td) {
|
||||
return td.m_subaddr_index == cryptonote::subaddress_index{ m_current_subaddress_account, index };
|
||||
}) != transfers.end();
|
||||
success_msg_writer() << index << " " << m_wallet->get_subaddress_as_str({m_current_subaddress_account, index}) << " " << (index == 0 ? tr("Primary address") : m_wallet->get_subaddress_label({m_current_subaddress_account, index})) << " " << (used ? tr("(used)") : "");
|
||||
success_msg_writer() << index << " " << m_wallet->get_subaddress_as_str({{m_current_subaddress_account, index}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot}) << " " << (index == 0 ? tr("Primary address") : m_wallet->get_subaddress_label({m_current_subaddress_account, index})) << " " << (used ? tr("(used)") : "");
|
||||
};
|
||||
|
||||
uint32_t index = 0;
|
||||
|
||||
@@ -53,8 +53,10 @@
|
||||
|
||||
#undef MONERO_DEFAULT_LOG_CATEGORY
|
||||
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.simplewallet"
|
||||
// Hardcode Monero's donation address (see #1447)
|
||||
constexpr const char SALVIUM_DONATION_ADDR[] = "888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H";
|
||||
|
||||
// Hardcode Salvium's donation address (pre-Carrot and post-Carrot)
|
||||
constexpr const char SALVIUM_DONATION_ADDR[] = "SaLvdVvjgeffnxRDFoEEgeSt3jVcU49W7byT6nawvJFVio9XR7V53tU4mdo3HjjKno2WApvqxmcmKLZyoeSZZQ6jVqSGj1TLsNL";
|
||||
constexpr const char SALVIUM_DONATION_ADDR_CARROT[] = "SC11sFBPrGmNuT8AiTPUW479BwkdPJwBxdjKEhZ96yDfFg3B4mawgcpE1YfCAa1zwzUiRTMP9eqB54av48ALhzUu1Q5QoPGUfh";
|
||||
|
||||
/*!
|
||||
* \namespace cryptonote
|
||||
@@ -107,6 +109,7 @@ namespace cryptonote
|
||||
boost::optional<epee::wipeable_string> open_wallet(const boost::program_options::variables_map& vm);
|
||||
bool close_wallet();
|
||||
|
||||
bool carrot_keys(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool viewkey(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool spendkey(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
bool seed(const std::vector<std::string> &args = std::vector<std::string>());
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_SALVIUM_VERSION "0.9.9-rc1"
|
||||
#define DEF_SALVIUM_VERSION "0.9.9-rc4"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.3.4"
|
||||
#define DEF_MONERO_RELEASE_NAME "One"
|
||||
|
||||
+185
-97
@@ -55,7 +55,7 @@ namespace wallet
|
||||
{
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static bool parse_tx_extra_for_scanning(const std::vector<std::uint8_t> &tx_extra,
|
||||
bool parse_tx_extra_for_scanning(const std::vector<std::uint8_t> &tx_extra,
|
||||
const std::size_t n_outputs,
|
||||
std::vector<crypto::public_key> &main_tx_ephemeral_pubkeys_out,
|
||||
std::vector<crypto::public_key> &additional_tx_ephemeral_pubkeys_out,
|
||||
@@ -142,13 +142,11 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_pre_car
|
||||
const std::optional<carrot::encrypted_payment_id_t> &encrypted_payment_id,
|
||||
const epee::span<const crypto::key_derivation> main_derivations,
|
||||
const epee::span<const crypto::key_derivation> additional_derivations,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
hw::device &hwdev)
|
||||
{
|
||||
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map = subaddress_keystore.get_all();
|
||||
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map = account.get_subaddress_map_cn();
|
||||
|
||||
boost::optional<cryptonote::subaddress_receive_info> receive_info;
|
||||
size_t main_deriv_idx;
|
||||
for (main_deriv_idx = 0; main_deriv_idx < std::max<size_t>(1, main_derivations.size()); ++main_deriv_idx)
|
||||
@@ -237,11 +235,15 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_pre_car
|
||||
//j
|
||||
const carrot::subaddress_index_extended subaddr_index{
|
||||
.index = {receive_info->index.major, receive_info->index.minor},
|
||||
.derive_type = carrot::AddressDeriveType::PreCarrot
|
||||
.derive_type = carrot::AddressDeriveType::PreCarrot,
|
||||
.is_return_spend_key = true
|
||||
};
|
||||
|
||||
// add the entry to our temporary subaddress map via the keystore
|
||||
subaddress_keystore.add(enote.onetime_address, {subaddr_index.index.major, subaddr_index.index.minor});
|
||||
// HERE BE DRAGONS!!!
|
||||
// SRCG: whilst the following code will work, it'd be better being moved to the TX_BUILDER code
|
||||
// add the entry to our subaddress map in case it's a change payment (false positives won't hurt us)
|
||||
account.insert_subaddresses({{enote.onetime_address, subaddr_index}});
|
||||
// LAND AHOY!!!
|
||||
|
||||
return enote_view_incoming_scan_info_t{
|
||||
.sender_extension_g = sender_extension_g,
|
||||
@@ -252,33 +254,74 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_pre_car
|
||||
.amount = amount,
|
||||
.amount_blinding_factor = amount_blinding_factor,
|
||||
.asset_type = enote.asset_type,
|
||||
.main_tx_pubkey_index = main_deriv_idx
|
||||
.main_tx_pubkey_index = main_deriv_idx,
|
||||
.is_carrot = false,
|
||||
.is_return = false
|
||||
};
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_coinbase_enote(
|
||||
const carrot::CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver_unctx,
|
||||
const crypto::public_key &main_address_spend_pubkey)
|
||||
const crypto::public_key &main_address_spend_pubkey,
|
||||
carrot::carrot_and_legacy_account &account)
|
||||
{
|
||||
enote_view_incoming_scan_info_t res;
|
||||
|
||||
bool found_in_return = false;
|
||||
if (!carrot::try_scan_carrot_coinbase_enote_receiver(enote,
|
||||
s_sender_receiver_unctx,
|
||||
main_address_spend_pubkey,
|
||||
res.sender_extension_g,
|
||||
res.sender_extension_t))
|
||||
return std::nullopt;
|
||||
{
|
||||
// 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 std::nullopt;
|
||||
|
||||
found_in_return = true;
|
||||
}
|
||||
|
||||
if (found_in_return) {
|
||||
// scan the return output
|
||||
crypto::public_key address_spend_pubkey;
|
||||
carrot::encrypted_amount_t amount_enc;
|
||||
crypto::secret_key amount_blinding_factor;
|
||||
rct::xmr_amount amount;
|
||||
if (!scan_return_output(
|
||||
enote.onetime_address,
|
||||
enote.enote_ephemeral_pubkey,
|
||||
enote.view_tag,
|
||||
enote.anchor_enc,
|
||||
amount_enc,
|
||||
std::nullopt, // no amount commitment for coinbase enotes
|
||||
account.get_return_output_map_ref()
|
||||
.at(enote.onetime_address).input_context,
|
||||
account,
|
||||
address_spend_pubkey,
|
||||
amount,
|
||||
amount_blinding_factor)
|
||||
) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
res.address_spend_pubkey = address_spend_pubkey;
|
||||
res.return_address = enote.onetime_address;
|
||||
res.is_return = true;
|
||||
} else {
|
||||
// we received a coinbase enote
|
||||
res.address_spend_pubkey = main_address_spend_pubkey;
|
||||
res.is_return = false;
|
||||
}
|
||||
|
||||
res.address_spend_pubkey = main_address_spend_pubkey;
|
||||
res.payment_id = crypto::null_hash;
|
||||
res.subaddr_index = carrot::subaddress_index_extended{{0, 0}};
|
||||
res.amount = enote.amount;
|
||||
res.asset_type = enote.asset_type;
|
||||
res.amount_blinding_factor = rct::I;
|
||||
res.main_tx_pubkey_index = 0;
|
||||
|
||||
res.is_carrot = true;
|
||||
return res;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -322,6 +365,8 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
res.amount_blinding_factor = rct::sk2rct(amount_blinding_factor_sk);
|
||||
res.main_tx_pubkey_index = 0;
|
||||
res.asset_type = enote.asset_type;
|
||||
res.is_carrot = true;
|
||||
res.is_return = false;
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -336,14 +381,17 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
const mx25519_pubkey &s_sender_receiver_unctx,
|
||||
const crypto::public_key &main_address_spend_pubkey,
|
||||
const carrot::view_incoming_key_device &k_view_dev,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore)
|
||||
carrot::carrot_and_legacy_account &account)
|
||||
{
|
||||
enote_view_incoming_scan_info_t res;
|
||||
|
||||
// assume not a return output
|
||||
res.is_return = false;
|
||||
|
||||
crypto::secret_key amount_blinding_factor_sk;
|
||||
carrot::payment_id_t payment_id;
|
||||
carrot::CarrotEnoteType dummy_enote_type;
|
||||
carrot::janus_anchor_t internal_message;
|
||||
if (!carrot::try_scan_carrot_enote_external_receiver(enote,
|
||||
encrypted_payment_id,
|
||||
s_sender_receiver_unctx,
|
||||
@@ -356,31 +404,48 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
amount_blinding_factor_sk,
|
||||
payment_id,
|
||||
dummy_enote_type))
|
||||
return std::nullopt;
|
||||
{
|
||||
if (!carrot::try_scan_carrot_enote_internal_receiver(enote,
|
||||
account,
|
||||
res.sender_extension_g,
|
||||
res.sender_extension_t,
|
||||
res.address_spend_pubkey,
|
||||
res.amount,
|
||||
amount_blinding_factor_sk,
|
||||
dummy_enote_type,
|
||||
internal_message,
|
||||
res.return_address,
|
||||
res.is_return))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map = subaddress_keystore.get_all();
|
||||
|
||||
const auto subaddr_it = subaddress_map.find(res.address_spend_pubkey);
|
||||
CHECK_AND_ASSERT_MES(subaddr_it != subaddress_map.cend(),
|
||||
std::nullopt,
|
||||
"view_incoming_scan_carrot_enote: carrot enote scanned successfully, "
|
||||
"but the recovered address spend pubkey was not found in the subaddress map");
|
||||
if (!res.is_return) {
|
||||
const auto subaddr_it = account.get_subaddress_map_ref().find(res.address_spend_pubkey);
|
||||
CHECK_AND_ASSERT_MES(subaddr_it != account.get_subaddress_map_ref().cend(),
|
||||
std::nullopt,
|
||||
"view_incoming_scan_carrot_enote: carrot enote scanned successfully, "
|
||||
"but the recovered address spend pubkey was not found in the subaddress map");
|
||||
|
||||
const carrot::subaddress_index_extended subaddr_index = subaddr_it->second;
|
||||
memset(&res.payment_id, 0, sizeof(res.payment_id));
|
||||
memcpy(&res.payment_id, &payment_id, sizeof(carrot::payment_id_t));
|
||||
res.subaddr_index = subaddr_index;
|
||||
} else {
|
||||
res.subaddr_index = {{0, 0}, carrot::AddressDeriveType::Carrot, true};
|
||||
}
|
||||
|
||||
const carrot::subaddress_index_extended subaddr_index = {{subaddr_it->second.major, subaddr_it->second.minor}};
|
||||
|
||||
memset(&res.payment_id, 0, sizeof(res.payment_id));
|
||||
memcpy(&res.payment_id, &payment_id, sizeof(carrot::payment_id_t));
|
||||
|
||||
res.subaddr_index = subaddr_index;
|
||||
res.amount_blinding_factor = rct::sk2rct(amount_blinding_factor_sk);
|
||||
res.main_tx_pubkey_index = 0;
|
||||
res.asset_type = enote.asset_type;
|
||||
res.is_carrot = true;
|
||||
|
||||
return res;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static void perform_ecdh_derivations(const epee::span<const crypto::public_key> main_tx_ephemeral_pubkeys,
|
||||
void perform_ecdh_derivations(const epee::span<const crypto::public_key> main_tx_ephemeral_pubkeys,
|
||||
const epee::span<const crypto::public_key> additional_tx_ephemeral_pubkeys,
|
||||
const crypto::secret_key &k_view_incoming,
|
||||
hw::device &hwdev,
|
||||
@@ -391,7 +456,7 @@ static void perform_ecdh_derivations(const epee::span<const crypto::public_key>
|
||||
main_derivations_out.clear();
|
||||
additional_derivations_out.clear();
|
||||
main_derivations_out.reserve(main_tx_ephemeral_pubkeys.size());
|
||||
additional_derivations_out.reserve(additional_derivations_out.size());
|
||||
additional_derivations_out.reserve(additional_tx_ephemeral_pubkeys.size());
|
||||
|
||||
if (is_carrot)
|
||||
{
|
||||
@@ -468,8 +533,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
const epee::span<const crypto::key_derivation> additional_derivations,
|
||||
const cryptonote::account_public_address &address,
|
||||
const carrot::view_incoming_key_device *k_view_dev,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
hw::device &hwdev)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(!main_derivations.empty() || !additional_derivations.empty(),
|
||||
@@ -495,7 +559,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
encrypted_payment_id,
|
||||
main_derivations,
|
||||
additional_derivations,
|
||||
subaddress_keystore,
|
||||
account,
|
||||
hwdev);
|
||||
|
||||
// copy long plaintext payment ID, if applicable
|
||||
@@ -515,7 +579,8 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
|
||||
return view_incoming_scan_carrot_coinbase_enote(enote,
|
||||
s_sender_receiver_unctx,
|
||||
address.m_spend_public_key);
|
||||
address.m_spend_public_key,
|
||||
account);
|
||||
}
|
||||
|
||||
std::optional<enote_view_incoming_scan_info_t> operator()(const carrot::CarrotEnoteV1 &enote) const
|
||||
@@ -540,7 +605,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
s_sender_receiver_unctx,
|
||||
address.m_spend_public_key,
|
||||
*k_view_dev,
|
||||
subaddress_keystore);
|
||||
account);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,8 +616,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
const epee::span<const crypto::key_derivation> additional_derivations;
|
||||
const cryptonote::account_public_address &address;
|
||||
const carrot::view_incoming_key_device *k_view_dev;
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map;
|
||||
tools::keystore &subaddress_keystore;
|
||||
carrot::carrot_and_legacy_account &account;
|
||||
hw::device &hwdev;
|
||||
};
|
||||
|
||||
@@ -564,7 +628,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
additional_derivations,
|
||||
address,
|
||||
k_view_dev,
|
||||
subaddress_keystore,
|
||||
account,
|
||||
hwdev
|
||||
},
|
||||
enote);
|
||||
@@ -580,8 +644,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
const epee::span<const crypto::key_derivation> additional_derivations,
|
||||
const cryptonote::account_public_address &address,
|
||||
const carrot::view_incoming_key_device *k_view_dev,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
hw::device &hwdev)
|
||||
{
|
||||
MoneroEnoteVariant enote;
|
||||
@@ -638,7 +701,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote(
|
||||
additional_derivations,
|
||||
address,
|
||||
k_view_dev,
|
||||
subaddress_keystore,
|
||||
account,
|
||||
hwdev);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -649,8 +712,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote_from_pre
|
||||
const std::size_t local_output_index,
|
||||
const cryptonote::account_public_address &address,
|
||||
const crypto::secret_key &k_view_incoming,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
hw::device &hwdev)
|
||||
{
|
||||
const bool is_carrot = carrot::is_carrot_transaction_v1(tx_prefix);
|
||||
@@ -703,7 +765,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote_from_pre
|
||||
epee::to_span(additional_derivations),
|
||||
address,
|
||||
&k_view_dev,
|
||||
subaddress_keystore,
|
||||
account,
|
||||
hwdev);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -714,9 +776,7 @@ void view_incoming_scan_transaction(
|
||||
const cryptonote::blobdata &tx_extra_nonce,
|
||||
const epee::span<const crypto::key_derivation> main_derivations,
|
||||
const epee::span<const crypto::key_derivation> additional_derivations,
|
||||
const cryptonote::account_keys &acc,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
const epee::span<std::optional<enote_view_incoming_scan_info_t>> enote_scan_infos_out)
|
||||
{
|
||||
const size_t n_outputs = tx.vout.size();
|
||||
@@ -725,31 +785,35 @@ void view_incoming_scan_transaction(
|
||||
"view_incoming_scan_transaction: enote scan span wrong length");
|
||||
|
||||
//! @TODO: HW device
|
||||
carrot::view_incoming_key_ram_borrowed_device k_view_dev(acc.m_view_secret_key);
|
||||
const bool is_carrot = carrot::is_carrot_transaction_v1(tx);
|
||||
carrot::view_incoming_key_ram_borrowed_device k_view_dev(
|
||||
is_carrot ? account.get_keys().k_view_incoming
|
||||
: account.get_keys().m_view_secret_key
|
||||
);
|
||||
const cryptonote::account_public_address &address =
|
||||
is_carrot ? account.get_keys().m_carrot_account_address : account.get_keys().m_account_address;
|
||||
|
||||
// do view-incoming scan for each output enotes
|
||||
for (size_t local_output_index = 0; local_output_index < n_outputs; ++local_output_index)
|
||||
{
|
||||
auto &enote_scan_info = const_cast<std::optional<enote_view_incoming_scan_info_t>&>(enote_scan_infos_out[local_output_index]);
|
||||
enote_scan_info = view_incoming_scan_enote(tx,
|
||||
local_output_index,
|
||||
main_tx_ephemeral_pubkeys,
|
||||
additional_tx_ephemeral_pubkeys,
|
||||
tx_extra_nonce,
|
||||
main_derivations,
|
||||
additional_derivations,
|
||||
acc.m_account_address,
|
||||
&k_view_dev,
|
||||
subaddress_keystore,
|
||||
acc.get_device());
|
||||
local_output_index,
|
||||
main_tx_ephemeral_pubkeys,
|
||||
additional_tx_ephemeral_pubkeys,
|
||||
tx_extra_nonce,
|
||||
main_derivations,
|
||||
additional_derivations,
|
||||
address,
|
||||
&k_view_dev,
|
||||
account,
|
||||
account.get_keys().get_device());
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void view_incoming_scan_transaction(
|
||||
const cryptonote::transaction &tx,
|
||||
const cryptonote::account_keys &acc,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
const epee::span<std::optional<enote_view_incoming_scan_info_t>> enote_scan_infos_out)
|
||||
{
|
||||
// 1. parse tx extra
|
||||
@@ -769,34 +833,37 @@ void view_incoming_scan_transaction(
|
||||
// 2. perform ECDH derivations
|
||||
std::vector<crypto::key_derivation> main_derivations;
|
||||
std::vector<crypto::key_derivation> additional_derivations;
|
||||
const bool is_carrot = carrot::is_carrot_transaction_v1(tx);
|
||||
perform_ecdh_derivations(epee::to_span(main_tx_ephemeral_pubkeys),
|
||||
epee::to_span(additional_tx_ephemeral_pubkeys),
|
||||
acc.m_view_secret_key,
|
||||
acc.get_device(),
|
||||
carrot::is_carrot_transaction_v1(tx),
|
||||
main_derivations,
|
||||
additional_derivations);
|
||||
epee::to_span(additional_tx_ephemeral_pubkeys),
|
||||
is_carrot ? account.get_keys().k_view_incoming : account.get_keys().m_view_secret_key,
|
||||
account.get_keys().get_device(),
|
||||
is_carrot,
|
||||
main_derivations,
|
||||
additional_derivations);
|
||||
|
||||
// 3. view-incoming scan output enotes
|
||||
view_incoming_scan_transaction(tx,
|
||||
epee::to_span(main_tx_ephemeral_pubkeys),
|
||||
epee::to_span(additional_tx_ephemeral_pubkeys),
|
||||
tx_extra_nonce,
|
||||
epee::to_span(main_derivations),
|
||||
epee::to_span(additional_derivations),
|
||||
acc,
|
||||
subaddress_keystore,
|
||||
enote_scan_infos_out);
|
||||
epee::to_span(main_tx_ephemeral_pubkeys),
|
||||
epee::to_span(additional_tx_ephemeral_pubkeys),
|
||||
tx_extra_nonce,
|
||||
epee::to_span(main_derivations),
|
||||
epee::to_span(additional_derivations),
|
||||
account,
|
||||
enote_scan_infos_out);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_transaction(
|
||||
const cryptonote::transaction &tx,
|
||||
const cryptonote::account_keys &acc,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore)
|
||||
carrot::carrot_and_legacy_account &account)
|
||||
{
|
||||
std::vector<std::optional<enote_view_incoming_scan_info_t>> res(tx.vout.size());
|
||||
view_incoming_scan_transaction(tx, acc, subaddress_keystore, epee::to_mut_span(res));
|
||||
const auto n_outputs = tx.vout.size();
|
||||
std::vector<std::optional<enote_view_incoming_scan_info_t>> res(n_outputs);
|
||||
if (n_outputs > 0)
|
||||
{
|
||||
view_incoming_scan_transaction(tx, account, epee::to_mut_span(res));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -821,11 +888,10 @@ std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_t
|
||||
tx_extra_nonce))
|
||||
MWARNING("Transaction extra has unsupported format: " << cryptonote::get_transaction_hash(tx));
|
||||
|
||||
tools::keystore keystore;
|
||||
keystore.add(address.m_spend_public_key, {});
|
||||
|
||||
// 3. do view-incoming scan for each output enotes
|
||||
hw::device &hwdev = hw::get_device("default");
|
||||
carrot::carrot_and_legacy_account dummy_account;
|
||||
dummy_account.insert_subaddresses({{address.m_spend_public_key, {{0, 0}, carrot::AddressDeriveType::Carrot, false}}});
|
||||
for (size_t local_output_index = 0; local_output_index < n_outputs; ++local_output_index)
|
||||
{
|
||||
auto &enote_scan_info = res[local_output_index];
|
||||
@@ -839,7 +905,7 @@ std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_t
|
||||
custom_additional_derivations,
|
||||
address,
|
||||
/*k_view_dev=*/nullptr,
|
||||
keystore,
|
||||
dummy_account,
|
||||
hwdev);
|
||||
}
|
||||
|
||||
@@ -857,11 +923,18 @@ bool is_long_payment_id(const crypto::hash &pid)
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
std::optional<crypto::key_image> try_derive_enote_key_image(
|
||||
const enote_view_incoming_scan_info_t &enote_scan_info,
|
||||
const cryptonote::account_keys &acc)
|
||||
{
|
||||
const carrot::carrot_and_legacy_account &acc)
|
||||
{
|
||||
// we skip the return output key image generation here to do it in process_new_scanned_transaction.
|
||||
if (!enote_scan_info.subaddr_index)
|
||||
return std::nullopt;
|
||||
|
||||
// if we have a carrot return enote, we return already derived key image
|
||||
if (enote_scan_info.is_carrot && enote_scan_info.is_return)
|
||||
{
|
||||
return acc.get_return_output_map_ref().at(enote_scan_info.return_address).key_image;
|
||||
}
|
||||
|
||||
// k^j_subext
|
||||
rct::key subaddress_extension;
|
||||
if (enote_scan_info.subaddr_index->index.is_subaddress())
|
||||
@@ -869,7 +942,13 @@ std::optional<crypto::key_image> try_derive_enote_key_image(
|
||||
const cryptonote::subaddress_index subaddr_index_cn{enote_scan_info.subaddr_index->index.major,
|
||||
enote_scan_info.subaddr_index->index.minor};
|
||||
subaddress_extension = rct::sk2rct(
|
||||
acc.get_device().get_subaddress_secret_key(acc.m_view_secret_key, subaddr_index_cn));
|
||||
acc.get_keys()
|
||||
.get_device()
|
||||
.get_subaddress_secret_key(
|
||||
enote_scan_info.is_carrot ? acc.get_keys().k_view_incoming : acc.get_keys().m_view_secret_key,
|
||||
subaddr_index_cn
|
||||
)
|
||||
);
|
||||
}
|
||||
else // !subaddr_index_cn.is_zero()
|
||||
{
|
||||
@@ -877,8 +956,10 @@ std::optional<crypto::key_image> try_derive_enote_key_image(
|
||||
}
|
||||
|
||||
// O = K^j_s + k^g_o G + k^t_o T
|
||||
rct::key onetime_address = rct::scalarmultKey(rct::pk2rct(crypto::get_T()),
|
||||
rct::sk2rct(enote_scan_info.sender_extension_t));
|
||||
rct::key onetime_address = rct::scalarmultKey(
|
||||
rct::pk2rct(crypto::get_T()),
|
||||
rct::sk2rct(enote_scan_info.sender_extension_t)
|
||||
);
|
||||
rct::addKeys1(onetime_address, rct::sk2rct(enote_scan_info.sender_extension_g), onetime_address);
|
||||
rct::addKeys(onetime_address, onetime_address, rct::pk2rct(enote_scan_info.address_spend_pubkey));
|
||||
|
||||
@@ -889,11 +970,18 @@ std::optional<crypto::key_image> try_derive_enote_key_image(
|
||||
//! @TODO: HW devices
|
||||
// x = k_s + k^j_subext + k^g_o
|
||||
rct::key x;
|
||||
sc_add(x.bytes,
|
||||
to_bytes(acc.m_spend_secret_key),
|
||||
to_bytes(enote_scan_info.sender_extension_g));
|
||||
sc_add(x.bytes, x.bytes, subaddress_extension.bytes);
|
||||
|
||||
if (enote_scan_info.is_carrot) {
|
||||
return acc.derive_key_image(enote_scan_info.address_spend_pubkey,
|
||||
enote_scan_info.sender_extension_g,
|
||||
enote_scan_info.sender_extension_t,
|
||||
rct::rct2pk(onetime_address));
|
||||
} else {
|
||||
sc_add(x.bytes,
|
||||
to_bytes(acc.get_keys().m_spend_secret_key),
|
||||
to_bytes(enote_scan_info.sender_extension_g));
|
||||
sc_add(x.bytes, x.bytes, subaddress_extension.bytes);
|
||||
}
|
||||
|
||||
// L = x I = (k_s + k^j_subext + k^g_o) Hp(O)
|
||||
return rct::rct2ki(rct::scalarmultKey(rct::pt2rct(ki_generator), x));
|
||||
}
|
||||
|
||||
+30
-13
@@ -31,13 +31,13 @@
|
||||
//local headers
|
||||
#include "carrot_core/carrot_enote_types.h"
|
||||
#include "carrot_core/device.h"
|
||||
#include "carrot_core/account.h"
|
||||
#include "carrot_impl/subaddress_index.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_basic/blobdatatype.h"
|
||||
#include "cryptonote_basic/subaddress_index.h"
|
||||
#include "cryptonote_basic/tx_extra.h"
|
||||
#include "common/keystore.h"
|
||||
#include "common/variant.h"
|
||||
|
||||
//third party headers
|
||||
@@ -75,6 +75,15 @@ struct enote_view_incoming_scan_info_t
|
||||
|
||||
// the cold signing code used to have a bug which added multiple main tx pubkeys to extra
|
||||
std::size_t main_tx_pubkey_index;
|
||||
|
||||
// whether this output is to a carrot address or not
|
||||
bool is_carrot;
|
||||
|
||||
// whether this output is a return output
|
||||
bool is_return;
|
||||
|
||||
// Kr = K_return + K_o
|
||||
crypto::public_key return_address;
|
||||
};
|
||||
|
||||
struct PreCarrotEnote
|
||||
@@ -97,6 +106,21 @@ using MoneroEnoteVariant = std::variant<PreCarrotEnote,
|
||||
carrot::CarrotCoinbaseEnoteV1,
|
||||
carrot::CarrotEnoteV1>;
|
||||
|
||||
|
||||
bool parse_tx_extra_for_scanning(const std::vector<std::uint8_t> &tx_extra,
|
||||
const std::size_t n_outputs,
|
||||
std::vector<crypto::public_key> &main_tx_ephemeral_pubkeys_out,
|
||||
std::vector<crypto::public_key> &additional_tx_ephemeral_pubkeys_out,
|
||||
cryptonote::blobdata &tx_extra_nonce_out);
|
||||
|
||||
void perform_ecdh_derivations(const epee::span<const crypto::public_key> main_tx_ephemeral_pubkeys,
|
||||
const epee::span<const crypto::public_key> additional_tx_ephemeral_pubkeys,
|
||||
const crypto::secret_key &k_view_incoming,
|
||||
hw::device &hwdev,
|
||||
const bool is_carrot,
|
||||
std::vector<crypto::key_derivation> &main_derivations_out,
|
||||
std::vector<crypto::key_derivation> &additional_derivations_out);
|
||||
|
||||
std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote_from_prefix(
|
||||
const cryptonote::transaction_prefix &tx_prefix,
|
||||
const rct::xmr_amount amount,
|
||||
@@ -104,8 +128,7 @@ std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_enote_from_pre
|
||||
const std::size_t local_output_index,
|
||||
const cryptonote::account_public_address &address,
|
||||
const crypto::secret_key &k_view_incoming,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
hw::device &hwdev);
|
||||
|
||||
void view_incoming_scan_transaction(
|
||||
@@ -115,21 +138,15 @@ void view_incoming_scan_transaction(
|
||||
const cryptonote::blobdata &tx_extra_nonce,
|
||||
const epee::span<const crypto::key_derivation> main_derivations,
|
||||
const epee::span<const crypto::key_derivation> additional_derivations,
|
||||
const cryptonote::account_keys &acc,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
const epee::span<std::optional<enote_view_incoming_scan_info_t>> enote_scan_infos_out);
|
||||
void view_incoming_scan_transaction(
|
||||
const cryptonote::transaction &tx,
|
||||
const cryptonote::account_keys &acc,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
const epee::span<std::optional<enote_view_incoming_scan_info_t>> enote_scan_infos_out);
|
||||
std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_transaction(
|
||||
const cryptonote::transaction &tx,
|
||||
const cryptonote::account_keys &acc,
|
||||
//const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
tools::keystore &subaddress_keystore);
|
||||
carrot::carrot_and_legacy_account &account);
|
||||
|
||||
std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_transaction_as_sender(
|
||||
const cryptonote::transaction &tx,
|
||||
@@ -141,6 +158,6 @@ bool is_long_payment_id(const crypto::hash &pid);
|
||||
|
||||
std::optional<crypto::key_image> try_derive_enote_key_image(
|
||||
const enote_view_incoming_scan_info_t &enote_scan_info,
|
||||
const cryptonote::account_keys &acc);
|
||||
const carrot::carrot_and_legacy_account &acc);
|
||||
} //namespace wallet
|
||||
} //namespace tools
|
||||
|
||||
+336
-153
@@ -47,6 +47,7 @@
|
||||
#include "ringct/bulletproofs_plus.h"
|
||||
#include "wallet/scanning_tools.cpp"
|
||||
#include "common/container_helpers.h"
|
||||
#include "carrot_core/payment_proposal.cpp"
|
||||
|
||||
//third party headers
|
||||
|
||||
@@ -81,16 +82,22 @@ static bool is_transfer_usable_for_input_selection(const wallet2::transfer_detai
|
||||
const uint64_t last_locked_block_index = cryptonote::get_last_locked_block_index(
|
||||
td.m_tx.unlock_time, td.m_block_height);
|
||||
*/
|
||||
// Reject locked outputs
|
||||
size_t blocks_locked_for = CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
|
||||
if (td.m_tx.type == cryptonote::transaction_type::MINER || td.m_tx.type == cryptonote::transaction_type::PROTOCOL)
|
||||
blocks_locked_for = CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
|
||||
return !td.m_spent
|
||||
&& td.m_key_image_known
|
||||
&& !td.m_key_image_partial
|
||||
&& !td.m_frozen
|
||||
&& (top_block_index >= td.m_block_height + blocks_locked_for)
|
||||
// && last_locked_block_index <= top_block_index
|
||||
&& td.m_subaddr_index.major == from_account
|
||||
&& (from_subaddresses.empty() || from_subaddresses.count(td.m_subaddr_index.minor) == 1)
|
||||
&& td.amount() >= ignore_below
|
||||
&& td.amount() <= ignore_above
|
||||
&& td.asset_type == "SAL1"
|
||||
;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -113,7 +120,7 @@ static bool build_payment_proposals(std::vector<carrot::CarrotPaymentProposalV1>
|
||||
.amount = tx_dest_entry.amount,
|
||||
.enote_type = carrot::CarrotEnoteType::PAYMENT
|
||||
},
|
||||
.subaddr_index = {subaddr_index, carrot::AddressDeriveType::PreCarrot} // @TODO: handle carrot
|
||||
.subaddr_index = {subaddr_index, carrot::AddressDeriveType::Carrot, false},
|
||||
});
|
||||
}
|
||||
else // not *known* self-send address
|
||||
@@ -173,11 +180,43 @@ static crypto::public_key find_change_address_spend_pubkey(
|
||||
CHECK_AND_ASSERT_THROW_MES(change_it != subaddress_map.cend(),
|
||||
"find_change_address_spend_pubkey: missing change address (index "
|
||||
<< subaddr_account << ",0) in subaddress map");
|
||||
|
||||
const auto change_it_2 = std::find_if(std::next(change_it), subaddress_map.cend(),
|
||||
[subaddr_account](const auto &p) { return p.second.major == subaddr_account && p.second.minor == 0; });
|
||||
CHECK_AND_ASSERT_THROW_MES(change_it_2 == subaddress_map.cend(),
|
||||
"find_change_address_spend_pubkey: provided CN subaddress map is malformed!!! At least two spend pubkeys map to "
|
||||
"index " << subaddr_account << ",0 in the subaddress map!");
|
||||
|
||||
return change_it->first;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static crypto::public_key find_change_address_spend_pubkey(
|
||||
const std::unordered_map<crypto::public_key, carrot::subaddress_index_extended> &subaddress_map,
|
||||
const std::uint32_t subaddr_account)
|
||||
{
|
||||
const auto change_it = std::find_if(subaddress_map.cbegin(), subaddress_map.cend(),
|
||||
[subaddr_account](const auto &p) {
|
||||
return p.second.index.major == subaddr_account &&
|
||||
p.second.index.minor == 0 &&
|
||||
p.second.derive_type == carrot::AddressDeriveType::Carrot &&
|
||||
p.second.is_return_spend_key == false;
|
||||
});
|
||||
CHECK_AND_ASSERT_THROW_MES(change_it != subaddress_map.cend(),
|
||||
"find_change_address_spend_pubkey: missing change address (index "
|
||||
<< subaddr_account << ",0) in subaddress map");
|
||||
|
||||
const auto change_it_2 = std::find_if(std::next(change_it), subaddress_map.cend(),
|
||||
[subaddr_account](const auto &p) {
|
||||
return p.second.index.major == subaddr_account &&
|
||||
p.second.index.minor == 0 &&
|
||||
p.second.derive_type == carrot::AddressDeriveType::Carrot &&
|
||||
p.second.is_return_spend_key == false;
|
||||
});
|
||||
CHECK_AND_ASSERT_THROW_MES(change_it_2 == subaddress_map.cend(),
|
||||
"find_change_address_spend_pubkey: provided subaddress map is malformed!!! At least two spend pubkeys map to "
|
||||
"index " << subaddr_account << ",0 in the subaddress map!");
|
||||
|
||||
return change_it->first;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -400,6 +439,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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,
|
||||
const uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices,
|
||||
wallet2::unique_index_container subtract_fee_from_outputs,
|
||||
@@ -407,17 +447,16 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
{
|
||||
wallet2::transfer_container unused_transfers;
|
||||
w.get_transfers(unused_transfers);
|
||||
const auto subaddress_map = w.get_subaddress_map_ref();
|
||||
|
||||
std::vector<carrot::CarrotTransactionProposalV1> tx_proposals;
|
||||
tx_proposals.reserve(dsts.size() / (FCMP_PLUS_PLUS_MAX_OUTPUTS - 1) + 1);
|
||||
tx_proposals.reserve(dsts.size() / (carrot::CARROT_MAX_TX_OUTPUTS - 1) + 1);
|
||||
|
||||
const crypto::public_key change_address_spend_pubkey
|
||||
= find_change_address_spend_pubkey(subaddress_map, subaddr_account);
|
||||
= find_change_address_spend_pubkey(w.get_account().get_subaddress_map_ref(), subaddr_account);
|
||||
|
||||
while (!dsts.empty())
|
||||
{
|
||||
const std::size_t num_dsts_to_complete = std::min<std::size_t>(dsts.size(), FCMP_PLUS_PLUS_MAX_OUTPUTS - 1);
|
||||
const std::size_t num_dsts_to_complete = std::min<std::size_t>(dsts.size(), carrot::CARROT_MAX_TX_OUTPUTS - 1);
|
||||
|
||||
// build payment proposals and subtractable info from last `num_dsts_to_complete` dsts
|
||||
std::vector<carrot::CarrotPaymentProposalV1> normal_payment_proposals;
|
||||
@@ -430,7 +469,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const bool is_selfsend = build_payment_proposals(normal_payment_proposals,
|
||||
selfsend_payment_proposals,
|
||||
dst,
|
||||
subaddress_map);
|
||||
w.get_account().get_subaddress_map_cn());
|
||||
if (subtract_fee_from_outputs.count(dsts.size() - 1))
|
||||
{
|
||||
if (is_selfsend)
|
||||
@@ -462,9 +501,10 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
fee_per_weight,
|
||||
fee_quantization_mask,
|
||||
extra,
|
||||
tx_type,
|
||||
std::move(select_inputs),
|
||||
change_address_spend_pubkey,
|
||||
{{subaddr_account, 0}, carrot::AddressDeriveType::PreCarrot}, //! @TODO: handle Carrot keys
|
||||
{{subaddr_account, 0}, carrot::AddressDeriveType::Carrot, false},
|
||||
subtractable_normal_payment_proposals,
|
||||
subtractable_selfsend_payment_proposals,
|
||||
tx_proposal);
|
||||
@@ -496,6 +536,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const std::vector<cryptonote::tx_destination_entry> &dsts,
|
||||
const std::uint32_t priority,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const std::uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices,
|
||||
const wallet2::unique_index_container &subtract_fee_from_outputs)
|
||||
@@ -524,6 +565,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
fee_per_weight,
|
||||
fee_quantization_mask,
|
||||
extra,
|
||||
tx_type,
|
||||
subaddr_account,
|
||||
subaddr_indices,
|
||||
subtract_fee_from_outputs,
|
||||
@@ -531,8 +573,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep(
|
||||
const wallet2::transfer_container &transfers,
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
wallet2 &w,
|
||||
const std::vector<crypto::key_image> &input_key_images,
|
||||
const cryptonote::account_public_address &address,
|
||||
const bool is_subaddress,
|
||||
@@ -540,12 +581,16 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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,
|
||||
const std::uint64_t top_block_index)
|
||||
{
|
||||
wallet2::transfer_container transfers;
|
||||
w.get_transfers(transfers);
|
||||
|
||||
const size_t n_inputs = input_key_images.size();
|
||||
CARROT_CHECK_AND_THROW(n_inputs, carrot::too_few_inputs, "no key images provided");
|
||||
CARROT_CHECK_AND_THROW(n_dests_per_tx, carrot::too_few_outputs, "sweep must have at least one destination");
|
||||
CARROT_CHECK_AND_THROW(n_dests_per_tx <= FCMP_PLUS_PLUS_MAX_OUTPUTS,
|
||||
CARROT_CHECK_AND_THROW(n_dests_per_tx <= carrot::CARROT_MAX_TX_OUTPUTS,
|
||||
carrot::too_many_outputs, "too many sweep destinations per transaction");
|
||||
|
||||
// Check that the key image is usable and isn't spent, collect amounts, and get subaddress account index
|
||||
@@ -571,26 +616,31 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
}
|
||||
|
||||
const crypto::public_key change_address_spend_pubkey
|
||||
= find_change_address_spend_pubkey(subaddress_map, subaddr_account);
|
||||
= find_change_address_spend_pubkey(w.get_account().get_subaddress_map_ref(), subaddr_account);
|
||||
|
||||
// get 1 payment proposal corresponding to (address, is_subaddres)
|
||||
std::vector<carrot::CarrotPaymentProposalV1> normal_payment_proposals;
|
||||
std::vector<carrot::CarrotPaymentProposalVerifiableSelfSendV1> selfsend_payment_proposals;
|
||||
for (size_t i = 0; i < n_dests_per_tx; ++i)
|
||||
{
|
||||
cryptonote::tx_destination_entry de;
|
||||
de.amount = 0;
|
||||
de.addr = address;
|
||||
de.is_subaddress = is_subaddress;
|
||||
de.asset_type = "SAL1";
|
||||
const bool is_selfsend_dest = build_payment_proposals(normal_payment_proposals,
|
||||
selfsend_payment_proposals,
|
||||
cryptonote::tx_destination_entry(/*amount=*/0, address, is_subaddress),
|
||||
subaddress_map);
|
||||
de,
|
||||
w.get_account().get_subaddress_map_cn());
|
||||
CHECK_AND_ASSERT_THROW_MES((is_selfsend_dest && selfsend_payment_proposals.size() == i+1)
|
||||
|| (!is_selfsend_dest && normal_payment_proposals.size() == i+1),
|
||||
__func__ << ": BUG in build_payment_proposals: incorrect count for payment proposal lists");
|
||||
}
|
||||
CARROT_CHECK_AND_THROW(normal_payment_proposals.size() < FCMP_PLUS_PLUS_MAX_OUTPUTS,
|
||||
CARROT_CHECK_AND_THROW(normal_payment_proposals.size() < carrot::CARROT_MAX_TX_OUTPUTS,
|
||||
carrot::too_many_outputs, "too many *outgoing* sweep destinations per tx, we also need 1 self-send output");
|
||||
|
||||
// make `n_txs` tx proposals with `n_output` payment proposals each
|
||||
const size_t n_txs = div_ceil<size_t>(n_inputs, FCMP_PLUS_PLUS_MAX_INPUTS);
|
||||
const size_t n_txs = div_ceil<size_t>(n_inputs, carrot::CARROT_MAX_TX_INPUTS);
|
||||
std::vector<carrot::CarrotTransactionProposalV1> tx_proposals(n_txs);
|
||||
size_t ki_idx = 0;
|
||||
for (carrot::CarrotTransactionProposalV1 &tx_proposal : tx_proposals)
|
||||
@@ -600,7 +650,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
selfsend_payment_proposals.back().proposal.enote_type = carrot::CarrotEnoteType::CHANGE;
|
||||
|
||||
// collect inputs for this tx
|
||||
const size_t ki_idx_end = std::min<size_t>(n_inputs, ki_idx + FCMP_PLUS_PLUS_MAX_INPUTS);
|
||||
const size_t ki_idx_end = std::min<size_t>(n_inputs, ki_idx + carrot::CARROT_MAX_TX_INPUTS);
|
||||
std::vector<carrot::CarrotSelectedInput> selected_inputs;
|
||||
selected_inputs.reserve(n_inputs - ki_idx_end);
|
||||
for (; ki_idx < ki_idx_end; ++ki_idx)
|
||||
@@ -611,10 +661,18 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
fee_per_weight,
|
||||
fee_quantization_mask,
|
||||
extra,
|
||||
tx_type,
|
||||
std::move(selected_inputs),
|
||||
change_address_spend_pubkey,
|
||||
{{subaddr_account, 0}, carrot::AddressDeriveType::PreCarrot}, //! @TODO: handle Carrot keys
|
||||
{{subaddr_account, 0}, carrot::AddressDeriveType::Carrot},
|
||||
tx_proposal);
|
||||
|
||||
// populate the sources
|
||||
std::vector<size_t> selected_transfer_indices_sorted;
|
||||
for (const auto &ki: tx_proposal.key_images_sorted) {
|
||||
selected_transfer_indices_sorted.push_back(w.get_transfer_details(ki));
|
||||
}
|
||||
tx_proposal.sources = get_sources(transfers, selected_transfer_indices_sorted, "SAL1", w);
|
||||
}
|
||||
|
||||
CARROT_CHECK_AND_THROW(ki_idx == input_key_images.size(),
|
||||
@@ -630,11 +688,9 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const bool is_subaddress,
|
||||
const size_t n_dests_per_tx,
|
||||
const std::uint32_t priority,
|
||||
const std::vector<uint8_t> &extra)
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type)
|
||||
{
|
||||
wallet2::transfer_container transfers;
|
||||
w.get_transfers(transfers);
|
||||
|
||||
const rct::xmr_amount fee_per_weight = w.get_base_fee(priority);
|
||||
const rct::xmr_amount fee_quantization_mask = w.get_fee_quantization_mask();
|
||||
|
||||
@@ -644,8 +700,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const std::uint64_t top_block_index = current_chain_height - 1;
|
||||
|
||||
return make_carrot_transaction_proposals_wallet2_sweep(
|
||||
transfers,
|
||||
w.get_subaddress_map_ref(),
|
||||
w,
|
||||
input_key_images,
|
||||
address,
|
||||
is_subaddress,
|
||||
@@ -653,12 +708,12 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
fee_per_weight,
|
||||
fee_quantization_mask,
|
||||
extra,
|
||||
tx_type,
|
||||
top_block_index);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep_all(
|
||||
const wallet2::transfer_container &transfers,
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
wallet2 &w,
|
||||
const rct::xmr_amount only_below,
|
||||
const cryptonote::account_public_address &address,
|
||||
const bool is_subaddress,
|
||||
@@ -666,10 +721,14 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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,
|
||||
const std::uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices,
|
||||
const std::uint64_t top_block_index)
|
||||
{
|
||||
wallet2::transfer_container transfers;
|
||||
w.get_transfers(transfers);
|
||||
|
||||
const std::unordered_map<crypto::key_image, size_t> unburned_transfers_by_key_image =
|
||||
collect_non_burned_transfers_by_key_image(transfers);
|
||||
|
||||
@@ -699,8 +758,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
CHECK_AND_ASSERT_THROW_MES(!input_key_images.empty(), __func__ << ": no usable transfers to sweep");
|
||||
|
||||
return make_carrot_transaction_proposals_wallet2_sweep(
|
||||
transfers,
|
||||
subaddress_map,
|
||||
w,
|
||||
input_key_images,
|
||||
address,
|
||||
is_subaddress,
|
||||
@@ -708,6 +766,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
fee_per_weight,
|
||||
fee_quantization_mask,
|
||||
extra,
|
||||
tx_type,
|
||||
top_block_index);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -719,12 +778,10 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const size_t n_dests_per_tx,
|
||||
const std::uint32_t priority,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const std::uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices)
|
||||
{
|
||||
wallet2::transfer_container transfers;
|
||||
w.get_transfers(transfers);
|
||||
|
||||
const rct::xmr_amount fee_per_weight = w.get_base_fee(priority);
|
||||
const rct::xmr_amount fee_quantization_mask = w.get_fee_quantization_mask();
|
||||
|
||||
@@ -734,8 +791,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const std::uint64_t top_block_index = current_chain_height - 1;
|
||||
|
||||
return make_carrot_transaction_proposals_wallet2_sweep_all(
|
||||
transfers,
|
||||
w.get_subaddress_map_ref(),
|
||||
w,
|
||||
only_below,
|
||||
address,
|
||||
is_subaddress,
|
||||
@@ -743,14 +799,202 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
fee_per_weight,
|
||||
fee_quantization_mask,
|
||||
extra,
|
||||
tx_type,
|
||||
subaddr_account,
|
||||
subaddr_indices,
|
||||
top_block_index);
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool get_address_openings_x_y(
|
||||
const cryptonote::transaction &tx,
|
||||
const cryptonote::tx_source_entry &src,
|
||||
const wallet2 &w,
|
||||
crypto::secret_key &x_out,
|
||||
crypto::secret_key &y_out)
|
||||
{
|
||||
// If the output is a return output, we can use the return output secret key
|
||||
// to derive x and y directly.
|
||||
const auto& return_output_map = w.get_account().get_return_output_map_ref();
|
||||
if (return_output_map.find(rct::rct2pk(src.outputs[src.real_output].second.dest)) != return_output_map.end())
|
||||
{
|
||||
const auto &return_output = return_output_map.at(rct::rct2pk(src.outputs[src.real_output].second.dest));
|
||||
x_out = return_output.x;
|
||||
y_out = return_output.y;
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<crypto::public_key> v_pubkeys{src.real_out_tx_key};
|
||||
const std::vector<crypto::public_key> v_pubkeys_empty{};
|
||||
const epee::span<const crypto::public_key> main_tx_ephemeral_pubkeys = (src.real_out_tx_key == crypto::null_pkey) ? epee::to_span(v_pubkeys_empty) : epee::to_span(v_pubkeys);
|
||||
const epee::span<const crypto::public_key> additional_tx_ephemeral_pubkeys = epee::to_span(src.real_out_additional_tx_keys);
|
||||
|
||||
// we have to try both internal and external derivations
|
||||
bool r = false;
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
// perform ECDH derivations
|
||||
std::vector<crypto::key_derivation> main_derivations;
|
||||
std::vector<crypto::key_derivation> additional_derivations;
|
||||
if (i == 0) {
|
||||
wallet::perform_ecdh_derivations(
|
||||
main_tx_ephemeral_pubkeys,
|
||||
additional_tx_ephemeral_pubkeys,
|
||||
w.get_account().get_keys().k_view_incoming,
|
||||
w.get_account().get_keys().get_device(),
|
||||
src.carrot,
|
||||
main_derivations,
|
||||
additional_derivations
|
||||
);
|
||||
} else {
|
||||
crypto::key_derivation main_derivation;
|
||||
memcpy(main_derivation.data, w.get_account().get_keys().s_view_balance.data, sizeof(crypto::secret_key));
|
||||
main_derivations.push_back(main_derivation);
|
||||
}
|
||||
|
||||
crypto::hash s_sender_receiver;
|
||||
const crypto::key_derivation &kd = main_derivations.size()
|
||||
? main_derivations[0]
|
||||
: additional_derivations[src.real_output_in_tx_index];
|
||||
const mx25519_pubkey s_sender_receiver_unctx = carrot::raw_byte_convert<mx25519_pubkey>(kd);
|
||||
|
||||
// ephemeral pubkeys
|
||||
const epee::span<const crypto::public_key> enote_ephemeral_pubkeys_pk =
|
||||
main_tx_ephemeral_pubkeys.empty() ? additional_tx_ephemeral_pubkeys : main_tx_ephemeral_pubkeys;
|
||||
const epee::span<const mx25519_pubkey> enote_ephemeral_pubkeys = {
|
||||
reinterpret_cast<const mx25519_pubkey*>(enote_ephemeral_pubkeys_pk.data()),
|
||||
enote_ephemeral_pubkeys_pk.size()
|
||||
};
|
||||
|
||||
const bool shared_ephemeral_pubkey = enote_ephemeral_pubkeys.size() == 1;
|
||||
const size_t ephemeral_pubkey_index = shared_ephemeral_pubkey ? 0 : src.real_output_in_tx_index;
|
||||
|
||||
// input_context
|
||||
carrot::input_context_t input_context;
|
||||
if (src.coinbase) {
|
||||
input_context = carrot::make_carrot_input_context_coinbase(src.block_index);
|
||||
} else {
|
||||
input_context = carrot::make_carrot_input_context(src.first_rct_key_image);
|
||||
}
|
||||
|
||||
// s^ctx_sr = H_32(s_sr, D_e, input_context)
|
||||
make_carrot_sender_receiver_secret(s_sender_receiver_unctx.data,
|
||||
enote_ephemeral_pubkeys[ephemeral_pubkey_index],
|
||||
input_context,
|
||||
s_sender_receiver);
|
||||
|
||||
// get the k_og and k_ot
|
||||
crypto::secret_key sender_extension_g_out;
|
||||
crypto::secret_key sender_extension_t_out;
|
||||
crypto::public_key address_spend_pubkey_out;
|
||||
carrot::payment_id_t nominal_payment_id_out;
|
||||
carrot::janus_anchor_t nominal_janus_anchor_out;
|
||||
carrot::encrypted_janus_anchor_t encrypted_janus_anchor;
|
||||
carrot::encrypted_payment_id_t encrypted_payment_id;
|
||||
carrot::scan_carrot_dest_info(
|
||||
rct::rct2pk(src.outputs[src.real_output].second.dest),
|
||||
src.outputs[src.real_output].second.mask,
|
||||
encrypted_janus_anchor,
|
||||
encrypted_payment_id,
|
||||
s_sender_receiver,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
address_spend_pubkey_out,
|
||||
nominal_payment_id_out,
|
||||
nominal_janus_anchor_out
|
||||
);
|
||||
r = w.get_account().try_searching_for_opening_for_onetime_address(
|
||||
address_spend_pubkey_out,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
x_out,
|
||||
y_out
|
||||
);
|
||||
|
||||
// If we found the opening, we can stop here
|
||||
if (r) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to obtain openings for onetime address");
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
void encrypt_change_index(
|
||||
const std::vector<carrot::CarrotPaymentProposalV1> &proposals,
|
||||
const std::vector<carrot::CarrotPaymentProposalSelfSendV1> &selfsend_proposal_cores,
|
||||
const crypto::key_image &tx_first_key_image,
|
||||
const size_t change_index,
|
||||
const std::unordered_map<crypto::public_key, size_t> &payments_indices,
|
||||
std::vector<uint8_t> &change_masks_out
|
||||
) {
|
||||
// 1. input context: input_context = "R" || KI_1
|
||||
const carrot::input_context_t input_context = carrot::make_carrot_input_context(tx_first_key_image);
|
||||
|
||||
// 2. collect proposals and selfsend proposals destinations
|
||||
std::vector<std::tuple<crypto::public_key, size_t, bool>> destinations;
|
||||
for (const auto &p : proposals) {
|
||||
destinations.emplace_back(p.destination.address_spend_pubkey, payments_indices.at(p.destination.address_spend_pubkey), true);
|
||||
}
|
||||
for (const auto &p : selfsend_proposal_cores) {
|
||||
destinations.emplace_back(p.destination_address_spend_pubkey, payments_indices.at(p.destination_address_spend_pubkey), false);
|
||||
}
|
||||
|
||||
// 3. sort by indices
|
||||
std::sort(destinations.begin(), destinations.end(),
|
||||
[](const auto &a, const auto &b) {
|
||||
return std::get<1>(a) < std::get<1>(b);
|
||||
}
|
||||
);
|
||||
|
||||
// 4. calculate change masks
|
||||
for (const auto &d: destinations) {
|
||||
// get shared secret
|
||||
mx25519_pubkey eph_pubkey;
|
||||
mx25519_pubkey s_sender_receiver_unctx;
|
||||
if (std::get<2>(d)) {
|
||||
// normal payment proposal
|
||||
const auto it = std::find_if(proposals.begin(), proposals.end(),
|
||||
[&d](const carrot::CarrotPaymentProposalV1 &p) {
|
||||
return p.destination.address_spend_pubkey == std::get<0>(d);
|
||||
});
|
||||
CHECK_AND_ASSERT_THROW_MES(it != proposals.end(), "Failed to find normal payment proposal");
|
||||
carrot::get_normal_proposal_ecdh_parts(
|
||||
*it,
|
||||
input_context,
|
||||
eph_pubkey,
|
||||
s_sender_receiver_unctx
|
||||
);
|
||||
} else {
|
||||
s_sender_receiver_unctx = crypto::rand<mx25519_pubkey>();
|
||||
}
|
||||
|
||||
// derive a scalar from the shared secret
|
||||
crypto::secret_key output_index_key;
|
||||
crypto::key_derivation output_index_derivation;
|
||||
memcpy(output_index_derivation.data, s_sender_receiver_unctx.data, sizeof(output_index_derivation.data));
|
||||
crypto::derivation_to_scalar(
|
||||
output_index_derivation,
|
||||
std::get<1>(d),
|
||||
output_index_key
|
||||
);
|
||||
|
||||
// Calculate the encrypted_change_index data for this output
|
||||
struct {
|
||||
char domain_separator[8];
|
||||
crypto::secret_key output_index_key;
|
||||
} eci_buf;
|
||||
std::memset(eci_buf.domain_separator, 0x0, sizeof(eci_buf.domain_separator));
|
||||
std::strncpy(eci_buf.domain_separator, "CHG_IDX", 8);
|
||||
eci_buf.output_index_key = output_index_key;
|
||||
crypto::secret_key eci_out;
|
||||
keccak((uint8_t *)&eci_buf, sizeof(eci_buf), (uint8_t*)&eci_out, sizeof(eci_out));
|
||||
uint8_t eci_data = change_index ^ eci_out.data[0];
|
||||
change_masks_out.push_back(eci_data);
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
const carrot::CarrotTransactionProposalV1 &tx_proposal,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const wallet2 &w)
|
||||
{
|
||||
const size_t n_inputs = tx_proposal.key_images_sorted.size();
|
||||
@@ -762,7 +1006,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
<< n_inputs << "-in " << n_outputs << "-out, with "
|
||||
<< tx_proposal.normal_payment_proposals.size() << " normal payment proposals, "
|
||||
<< tx_proposal.selfsend_payment_proposals.size() << " self-send payment proposals, and a fee of "
|
||||
<< tx_proposal.fee << " pXMR");
|
||||
<< cryptonote::print_money(tx_proposal.fee) << " SAL1");
|
||||
|
||||
wallet2::transfer_container transfers;
|
||||
w.get_transfers(transfers);
|
||||
@@ -776,23 +1020,28 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
|
||||
//! @TODO: HW device
|
||||
carrot::cryptonote_hierarchy_address_device_ram_borrowed addr_dev(
|
||||
acc_keys.m_account_address.m_spend_public_key,
|
||||
acc_keys.m_view_secret_key);
|
||||
acc_keys.m_carrot_account_address.m_spend_public_key,
|
||||
acc_keys.k_view_incoming);
|
||||
|
||||
// finalize enotes
|
||||
LOG_PRINT_L3("Getting output enote proposals");
|
||||
std::vector<carrot::RCTOutputEnoteProposal> output_enote_proposals;
|
||||
carrot::encrypted_payment_id_t encrypted_payment_id;
|
||||
size_t change_index;
|
||||
carrot::RCTOutputEnoteProposal return_enote_out;
|
||||
std::unordered_map<crypto::public_key, size_t> payments_indices;
|
||||
carrot::get_output_enote_proposals(tx_proposal.normal_payment_proposals,
|
||||
selfsend_payment_proposal_cores,
|
||||
tx_proposal.dummy_encrypted_payment_id,
|
||||
nullptr,
|
||||
&w.get_account().s_view_balance_dev,
|
||||
&addr_dev,
|
||||
tx_proposal.key_images_sorted.at(0),
|
||||
output_enote_proposals,
|
||||
return_enote_out,
|
||||
encrypted_payment_id,
|
||||
tx_proposal.tx_type,
|
||||
change_index,
|
||||
payments_indices,
|
||||
nullptr);
|
||||
CHECK_AND_ASSERT_THROW_MES(output_enote_proposals.size() == n_outputs,
|
||||
"finalize_all_proofs_from_transfer_details: unexpected number of output enote proposals");
|
||||
@@ -816,15 +1065,26 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
for (size_t i = 0; i < enotes.size(); ++i)
|
||||
enotes[i] = output_enote_proposals.at(i).enote;
|
||||
|
||||
// encrypt change index per output
|
||||
std::vector<uint8_t> change_masks;
|
||||
encrypt_change_index(
|
||||
tx_proposal.normal_payment_proposals,
|
||||
selfsend_payment_proposal_cores,
|
||||
tx_proposal.key_images_sorted.at(0),
|
||||
change_index,
|
||||
payments_indices,
|
||||
change_masks);
|
||||
|
||||
// serialize transaction
|
||||
cryptonote::transaction tx = carrot::store_carrot_to_transaction_v1(enotes,
|
||||
tx_proposal.key_images_sorted,
|
||||
tx_proposal.sources,
|
||||
tx_proposal.fee,
|
||||
tx_proposal.tx_type,
|
||||
tx_proposal.amount_burnt,
|
||||
change_masks,
|
||||
return_enote_out,
|
||||
encrypted_payment_id);
|
||||
tx.source_asset_type = "SAL1";
|
||||
tx.destination_asset_type = "SAL1";
|
||||
tx.type = tx_type;
|
||||
|
||||
// aliases
|
||||
hw::device &hwdev = acc_keys.get_device();
|
||||
@@ -836,97 +1096,21 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
inSk.reserve(sources.size());
|
||||
std::vector<uint64_t> inamounts;
|
||||
std::vector<unsigned int> index;
|
||||
for (size_t i = 0; i < sources.size(); ++i)
|
||||
for (const auto& src: sources)
|
||||
{
|
||||
amount_in += sources[i].amount;
|
||||
inamounts.push_back(sources[i].amount);
|
||||
index.push_back(sources[i].real_output);
|
||||
amount_in += src.amount;
|
||||
inamounts.push_back(src.amount);
|
||||
index.push_back(src.real_output);
|
||||
|
||||
// inSk: (x, y, mask)
|
||||
rct::carrot_ctkey ctkey;
|
||||
ctkey.mask = sources[i].mask;
|
||||
if (sources[i].carrot) {
|
||||
|
||||
const epee::span<const crypto::public_key> main_tx_ephemeral_pubkeys =
|
||||
epee::to_span(std::vector<crypto::public_key>{sources[i].real_out_tx_key});
|
||||
const epee::span<const crypto::public_key> additional_tx_ephemeral_pubkeys =
|
||||
epee::to_span(sources[i].real_out_additional_tx_keys);
|
||||
|
||||
// 2. perform ECDH derivations
|
||||
std::vector<crypto::key_derivation> main_derivations;
|
||||
std::vector<crypto::key_derivation> additional_derivations;
|
||||
wallet::perform_ecdh_derivations(
|
||||
main_tx_ephemeral_pubkeys,
|
||||
additional_tx_ephemeral_pubkeys,
|
||||
acc_keys.m_view_secret_key,
|
||||
hwdev,
|
||||
carrot::is_carrot_transaction_v1(tx),
|
||||
main_derivations,
|
||||
additional_derivations
|
||||
);
|
||||
|
||||
crypto::hash s_sender_receiver;
|
||||
const crypto::key_derivation &kd = main_derivations.size()
|
||||
? main_derivations[0]
|
||||
: additional_derivations[sources[i].real_output_in_tx_index];
|
||||
const mx25519_pubkey s_sender_receiver_unctx = carrot::raw_byte_convert<mx25519_pubkey>(kd);
|
||||
|
||||
// ephemeral pubkeys
|
||||
const epee::span<const crypto::public_key> enote_ephemeral_pubkeys_pk =
|
||||
main_tx_ephemeral_pubkeys.empty() ? additional_tx_ephemeral_pubkeys : main_tx_ephemeral_pubkeys;
|
||||
const epee::span<const mx25519_pubkey> enote_ephemeral_pubkeys = {
|
||||
reinterpret_cast<const mx25519_pubkey*>(enote_ephemeral_pubkeys_pk.data()),
|
||||
enote_ephemeral_pubkeys_pk.size()
|
||||
};
|
||||
|
||||
const bool shared_ephemeral_pubkey = enote_ephemeral_pubkeys.size() == 1;
|
||||
const size_t ephemeral_pubkey_index = shared_ephemeral_pubkey ? 0 : sources[i].real_output_in_tx_index;
|
||||
|
||||
// input_context
|
||||
carrot::input_context_t input_context;
|
||||
if (sources[i].coinbase) {
|
||||
input_context = carrot::make_carrot_input_context_coinbase(sources[i].block_index);
|
||||
} else {
|
||||
input_context = carrot::make_carrot_input_context(sources[i].first_rct_key_image);
|
||||
}
|
||||
|
||||
// s^ctx_sr = H_32(s_sr, D_e, input_context)
|
||||
make_carrot_sender_receiver_secret(s_sender_receiver_unctx.data,
|
||||
enote_ephemeral_pubkeys[ephemeral_pubkey_index],
|
||||
input_context,
|
||||
s_sender_receiver);
|
||||
|
||||
// get the k_og and k_ot
|
||||
crypto::secret_key sender_extension_g_out;
|
||||
crypto::secret_key sender_extension_t_out;
|
||||
crypto::public_key address_spend_pubkey_out;
|
||||
carrot::payment_id_t nominal_payment_id_out;
|
||||
carrot::janus_anchor_t nominal_janus_anchor_out;
|
||||
carrot::encrypted_janus_anchor_t encrypted_janus_anchor;
|
||||
carrot::encrypted_payment_id_t encrypted_payment_id;
|
||||
carrot::scan_carrot_dest_info(
|
||||
rct::rct2pk(sources[i].outputs[sources[i].real_output].second.dest),
|
||||
sources[i].outputs[sources[i].real_output].second.mask,
|
||||
encrypted_janus_anchor,
|
||||
encrypted_payment_id,
|
||||
s_sender_receiver,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
address_spend_pubkey_out,
|
||||
nominal_payment_id_out,
|
||||
nominal_janus_anchor_out
|
||||
);
|
||||
ctkey.mask = src.mask;
|
||||
if (src.carrot) {
|
||||
|
||||
crypto::secret_key x, y;
|
||||
bool r = w.get_carrot_account().try_searching_for_opening_for_onetime_address(
|
||||
sources[i].address_spend_pubkey,
|
||||
sender_extension_g_out,
|
||||
sender_extension_t_out,
|
||||
x,
|
||||
y
|
||||
);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error,
|
||||
"Failed to search for opening for onetime address");
|
||||
THROW_WALLET_EXCEPTION_IF(!get_address_openings_x_y(tx, src, w, x, y),
|
||||
error::wallet_internal_error, "Failed to get x and y for input");
|
||||
|
||||
ctkey.x = rct::sk2rct(x);
|
||||
ctkey.y = rct::sk2rct(y);
|
||||
} else {
|
||||
@@ -934,21 +1118,21 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
cryptonote::keypair in_ephemeral;
|
||||
crypto::key_image img;
|
||||
rct::salvium_input_data_t sid;
|
||||
const auto& out_key = reinterpret_cast<const crypto::public_key&>(sources[i].outputs[sources[i].real_output].second.dest);
|
||||
bool use_origin_data = (sources[i].origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
|
||||
sid.origin_tx_type = sources[i].origin_tx_data.tx_type;
|
||||
const auto& out_key = reinterpret_cast<const crypto::public_key&>(src.outputs[src.real_output].second.dest);
|
||||
bool use_origin_data = (src.origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
|
||||
sid.origin_tx_type = src.origin_tx_data.tx_type;
|
||||
bool r = cryptonote::generate_key_image_helper(
|
||||
w.get_account().get_keys(),
|
||||
w.get_subaddress_map_ref(),
|
||||
w.get_account().get_subaddress_map_cn(),
|
||||
out_key,
|
||||
sources[i].real_out_tx_key,
|
||||
sources[i].real_out_additional_tx_keys,
|
||||
sources[i].real_output_in_tx_index,
|
||||
src.real_out_tx_key,
|
||||
src.real_out_additional_tx_keys,
|
||||
src.real_output_in_tx_index,
|
||||
in_ephemeral,
|
||||
img,
|
||||
hwdev,
|
||||
use_origin_data,
|
||||
sources[i].origin_tx_data, sid
|
||||
src.origin_tx_data, sid
|
||||
);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image helper");
|
||||
|
||||
@@ -990,7 +1174,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
const carrot::RCTOutputEnoteProposal &change_enote_proposal = output_enote_proposals.at(change_index);
|
||||
const carrot::input_context_t input_context = carrot::make_carrot_input_context(tx_proposal.key_images_sorted.at(0));
|
||||
crypto::hash s_sender_receiver;
|
||||
w.get_carrot_account().s_view_balance_dev.make_internal_sender_receiver_secret(
|
||||
w.get_account().s_view_balance_dev.make_internal_sender_receiver_secret(
|
||||
change_enote_proposal.enote.enote_ephemeral_pubkey,
|
||||
input_context,
|
||||
s_sender_receiver);
|
||||
@@ -999,7 +1183,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
crypto::secret_key sender_extension_t;
|
||||
carrot::make_carrot_onetime_address_extension_t(s_sender_receiver, change_enote_proposal.enote.amount_commitment, sender_extension_t);
|
||||
crypto::secret_key change_x, change_y;
|
||||
bool r = w.get_carrot_account().try_searching_for_opening_for_onetime_address(
|
||||
bool r = w.get_account().try_searching_for_opening_for_onetime_address(
|
||||
change_address_spend_pubkey,
|
||||
sender_extension_g,
|
||||
sender_extension_t,
|
||||
@@ -1007,7 +1191,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
change_y
|
||||
);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error,
|
||||
"Failed to search for opening for onetime address");
|
||||
"Failed to obtain opening for onetime change address");
|
||||
|
||||
// mixRing indexing is done the other way round for simple
|
||||
rct::ctkeyM mixRing(sources.size());
|
||||
@@ -1020,9 +1204,6 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
}
|
||||
}
|
||||
|
||||
// fee
|
||||
uint64_t fee = amount_in - amount_out - tx.amount_burnt;
|
||||
|
||||
// bpp
|
||||
tx.rct_signatures.p.bulletproofs_plus.push_back(
|
||||
rct::bulletproof_plus_PROVE(outamounts, output_amount_blinding_factors)
|
||||
@@ -1037,12 +1218,12 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
rct::hash2rct(tx_prefix_hash),
|
||||
inSk,
|
||||
destinations,
|
||||
tx_type,
|
||||
tx_proposal.tx_type,
|
||||
"SAL1",
|
||||
destination_asset_types,
|
||||
inamounts,
|
||||
outamounts,
|
||||
fee,
|
||||
tx_proposal.fee,
|
||||
mixRing,
|
||||
index,
|
||||
outSk,
|
||||
@@ -1064,16 +1245,24 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
wallet2::pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionProposalV1 &tx_proposal,
|
||||
const wallet2::transfer_container &transfers,
|
||||
const crypto::secret_key &k_view,
|
||||
hw::device &hwdev)
|
||||
const carrot::carrot_and_legacy_account &account)
|
||||
{
|
||||
const std::size_t n_inputs = tx_proposal.key_images_sorted.size();
|
||||
const std::size_t n_outputs = tx_proposal.normal_payment_proposals.size() +
|
||||
tx_proposal.selfsend_payment_proposals.size();
|
||||
const bool shared_ephemeral_pubkey = n_outputs == 2;
|
||||
|
||||
CARROT_CHECK_AND_THROW(
|
||||
tx_proposal.tx_type != cryptonote::transaction_type::UNSET,
|
||||
carrot::missing_components,
|
||||
"make_pending_carrot_tx: tx proposal has unset tx type"
|
||||
);
|
||||
CARROT_CHECK_AND_THROW(n_inputs >= 1, carrot::too_few_inputs, "carrot tx proposal missing inputs");
|
||||
CARROT_CHECK_AND_THROW(n_outputs >= 2, carrot::too_few_outputs, "carrot tx proposal missing outputs");
|
||||
if (tx_proposal.tx_type == cryptonote::transaction_type::STAKE || tx_proposal.tx_type == cryptonote::transaction_type::BURN) {
|
||||
CARROT_CHECK_AND_THROW(n_outputs == 1, carrot::too_few_outputs, "carrot tx proposal doesn't have correct number of outputs");
|
||||
} else {
|
||||
CARROT_CHECK_AND_THROW(n_outputs >= 2, carrot::too_few_outputs, "carrot tx proposal missing outputs");
|
||||
}
|
||||
|
||||
const crypto::key_image &tx_first_key_image = tx_proposal.key_images_sorted.at(0);
|
||||
|
||||
@@ -1097,16 +1286,13 @@ wallet2::pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionPropos
|
||||
key_images_string << ki;
|
||||
}
|
||||
|
||||
//! @TODO: HW device
|
||||
carrot::view_incoming_key_ram_borrowed_device k_view_dev(k_view);
|
||||
|
||||
// get order of payment proposals
|
||||
std::vector<carrot::RCTOutputEnoteProposal> output_enote_proposals;
|
||||
carrot::encrypted_payment_id_t encrypted_payment_id;
|
||||
std::vector<std::pair<bool, std::size_t>> sorted_payment_proposal_indices;
|
||||
carrot::get_output_enote_proposals_from_proposal_v1(tx_proposal,
|
||||
/*s_view_balance_dev=*/nullptr,
|
||||
&k_view_dev,
|
||||
&account.k_view_incoming_dev,
|
||||
output_enote_proposals,
|
||||
encrypted_payment_id,
|
||||
&sorted_payment_proposal_indices);
|
||||
@@ -1136,7 +1322,7 @@ wallet2::pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionPropos
|
||||
if (is_selfsend)
|
||||
{
|
||||
dest = make_tx_destination_entry(tx_proposal.selfsend_payment_proposals.at(payment_idx.second),
|
||||
k_view_dev);
|
||||
account.k_view_incoming_dev);
|
||||
ephemeral_privkeys.push_back(crypto::null_skey);
|
||||
}
|
||||
else // !is_selfsend
|
||||
@@ -1196,15 +1382,12 @@ wallet2::pending_tx finalize_all_proofs_from_transfer_details_as_pending_tx(
|
||||
const wallet2::transfer_container &transfers,
|
||||
const wallet2 &w)
|
||||
{
|
||||
const auto acc_keys = w.get_account().get_keys();
|
||||
wallet2::pending_tx ptx = make_pending_carrot_tx(tx_proposal,
|
||||
transfers,
|
||||
acc_keys.m_view_secret_key,
|
||||
acc_keys.get_device());
|
||||
w.get_account());
|
||||
|
||||
ptx.tx = finalize_all_proofs_from_transfer_details(
|
||||
tx_proposal,
|
||||
cryptonote::transaction_type::TRANSFER, // TODO:take this as a parameter
|
||||
w
|
||||
);
|
||||
|
||||
|
||||
+10
-12
@@ -63,6 +63,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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,
|
||||
const uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices,
|
||||
wallet2::unique_index_container subtract_fee_from_outputs,
|
||||
@@ -72,13 +73,13 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const std::vector<cryptonote::tx_destination_entry> &dsts,
|
||||
const std::uint32_t priority,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const std::uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices,
|
||||
const wallet2::unique_index_container &subtract_fee_from_outputs);
|
||||
|
||||
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep(
|
||||
const wallet2::transfer_container &transfers,
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
wallet2 &w,
|
||||
const std::vector<crypto::key_image> &input_key_images,
|
||||
const cryptonote::account_public_address &address,
|
||||
const bool is_subaddress,
|
||||
@@ -86,6 +87,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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,
|
||||
const std::uint64_t top_block_index);
|
||||
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep(
|
||||
wallet2 &w,
|
||||
@@ -94,11 +96,11 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const bool is_subaddress,
|
||||
const size_t n_dests_per_tx,
|
||||
const std::uint32_t priority,
|
||||
const std::vector<uint8_t> &extra);
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type);
|
||||
|
||||
std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposals_wallet2_sweep_all(
|
||||
const wallet2::transfer_container &transfers,
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> &subaddress_map,
|
||||
wallet2 &w,
|
||||
const rct::xmr_amount only_below,
|
||||
const cryptonote::account_public_address &address,
|
||||
const bool is_subaddress,
|
||||
@@ -106,6 +108,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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,
|
||||
const std::uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices,
|
||||
const std::uint64_t top_block_index);
|
||||
@@ -117,23 +120,18 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const size_t n_dests_per_tx,
|
||||
const std::uint32_t priority,
|
||||
const std::vector<uint8_t> &extra,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const std::uint32_t subaddr_account,
|
||||
const std::set<uint32_t> &subaddr_indices);
|
||||
wallet2::pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionProposalV1 &tx_proposal,
|
||||
const wallet2::transfer_container &transfers,
|
||||
const crypto::secret_key &k_view,
|
||||
hw::device &hwdev);
|
||||
const carrot::carrot_and_legacy_account &account);
|
||||
|
||||
cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
const carrot::CarrotTransactionProposalV1 &tx_proposal,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const wallet2 &w);
|
||||
|
||||
wallet2::pending_tx make_pending_carrot_tx(const carrot::CarrotTransactionProposalV1 &tx_proposal,
|
||||
const wallet2::transfer_container &transfers,
|
||||
const crypto::secret_key &k_view,
|
||||
hw::device &hwdev);
|
||||
|
||||
wallet2::pending_tx finalize_all_proofs_from_transfer_details_as_pending_tx(
|
||||
const carrot::CarrotTransactionProposalV1 &tx_proposal,
|
||||
const wallet2::transfer_container &transfers,
|
||||
|
||||
+255
-257
@@ -97,6 +97,8 @@ using namespace epee;
|
||||
#include "net/socks_connect.h"
|
||||
#include "carrot_impl/format_utils.h"
|
||||
#include "tx_builder.h"
|
||||
#include "scanning_tools.h"
|
||||
#include "carrot_core/scan.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -1582,10 +1584,15 @@ crypto::public_key wallet2::get_subaddress_spend_public_key(const cryptonote::su
|
||||
return hwdev.get_subaddress_spend_public_key(m_account.get_keys(), index);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string wallet2::get_subaddress_as_str(const cryptonote::subaddress_index& index) const
|
||||
std::string wallet2::get_subaddress_as_str(const carrot::subaddress_index_extended& subaddr) const
|
||||
{
|
||||
cryptonote::account_public_address address = get_subaddress(index);
|
||||
return cryptonote::get_account_address_as_str(m_nettype, !index.is_zero(), address);
|
||||
carrot::CarrotDestinationV1 address = m_account.subaddress(subaddr);
|
||||
|
||||
// Build the cryptonote::account_public_address
|
||||
account_public_address addr{address.address_spend_pubkey, address.address_view_pubkey};
|
||||
|
||||
// change this code into base 58
|
||||
return cryptonote::get_account_address_as_str(m_nettype, address.is_subaddress, addr, subaddr.derive_type == carrot::AddressDeriveType::Carrot);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::string wallet2::get_integrated_address_as_str(const crypto::hash8& payment_id) const
|
||||
@@ -2426,7 +2433,7 @@ void wallet2::scan_key_image(const wallet::enote_view_incoming_scan_info_t &enot
|
||||
}
|
||||
}
|
||||
|
||||
ki_out = wallet::try_derive_enote_key_image(enote_scan_info, m_account.get_keys());
|
||||
ki_out = wallet::try_derive_enote_key_image(enote_scan_info, m_account);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::process_new_transaction(
|
||||
@@ -2447,11 +2454,9 @@ void wallet2::process_new_transaction(
|
||||
const size_t n_outputs = tx.vout.size();
|
||||
|
||||
// view-incoming scan enotes
|
||||
tools::keystore keystore(m_subaddresses);
|
||||
const std::vector<std::optional<wallet::enote_view_incoming_scan_info_t>> enote_scan_infos =
|
||||
wallet::view_incoming_scan_transaction(tx,
|
||||
this->m_account.get_keys(),
|
||||
keystore);
|
||||
this->m_account);
|
||||
|
||||
// if view-incoming scan was successful, try deriving the key image
|
||||
bool password_failure = false;
|
||||
@@ -2534,23 +2539,20 @@ void wallet2::process_new_scanned_transaction(
|
||||
}
|
||||
|
||||
bool notify = false;
|
||||
// per receiving subaddress index
|
||||
// per receiving subaddress index -> (asset type, amount, one time address)
|
||||
std::unordered_map<cryptonote::subaddress_index, std::map<std::string, uint64_t>> tx_money_got_in_outs;
|
||||
std::unordered_map<cryptonote::subaddress_index, amounts_container> tx_amounts_individual_outs;
|
||||
std::unordered_map<cryptonote::subaddress_index, std::vector<std::tuple<uint64_t, crypto::public_key>>> tx_amounts_individual_outs;
|
||||
|
||||
// Note that this includes any 0-amount outputs, which we keep track of for background scanning
|
||||
bool received_an_output = false;
|
||||
|
||||
crypto::hash payment_id = null_hash;
|
||||
|
||||
// for each for scanned output...
|
||||
for (size_t local_output_index = 0; local_output_index < n_scanned_enotes; ++local_output_index)
|
||||
{
|
||||
const auto &enote_scan_info_local = enote_scan_infos[local_output_index];
|
||||
bool is_protocol = (tx.type == cryptonote::transaction_type::PROTOCOL);
|
||||
if (!is_protocol)
|
||||
if (!enote_scan_info_local || !enote_scan_info_local->subaddr_index)
|
||||
continue;
|
||||
const auto &enote_scan_info = enote_scan_infos[local_output_index];
|
||||
if (!enote_scan_info || !enote_scan_info->subaddr_index)
|
||||
continue;
|
||||
|
||||
received_an_output = true;
|
||||
|
||||
@@ -2561,113 +2563,18 @@ void wallet2::process_new_scanned_transaction(
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t td_origin_idx = (uint64_t)-1;
|
||||
wallet::enote_view_incoming_scan_info_t enote_scan_info_protocol;
|
||||
if (is_protocol) {
|
||||
|
||||
// Check that it is intended for us
|
||||
if (!m_salvium_txs.count(onetime_address))
|
||||
continue;
|
||||
|
||||
// Get the origin TX details
|
||||
td_origin_idx = m_salvium_txs.at(onetime_address);
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin_idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol TX origin in m_transfers");
|
||||
const transfer_details &td_origin = m_transfers[td_origin_idx];
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.type != cryptonote::transaction_type::AUDIT &&
|
||||
td_origin.m_tx.type != cryptonote::transaction_type::STAKE,
|
||||
error::wallet_internal_error,
|
||||
"incorrect TX type for protocol_tx origin in m_transfers");
|
||||
|
||||
// Perform the correct sanity checks needed for each type of origin TX
|
||||
if (td_origin.m_tx.type == cryptonote::transaction_type::STAKE) {
|
||||
|
||||
// Check the age of the TX
|
||||
uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD;
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin.m_block_height != height - stake_lock_period - 1,
|
||||
error::wallet_internal_error,
|
||||
"STAKE TX payout at incorrect height: found at " + std::to_string(height) +
|
||||
", but expected at " + std::to_string(td_origin.m_block_height + stake_lock_period + 1));
|
||||
|
||||
// Check the amount
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.amount_burnt > tx.vout[local_output_index].amount,
|
||||
error::wallet_internal_error,
|
||||
"STAKE TX payout (" + print_money(tx.vout[local_output_index].amount) +
|
||||
") is less than staked amount " + print_money(td_origin.m_tx.amount_burnt));
|
||||
|
||||
// Populate the dummy enote_scan_info struct
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(td_origin.m_tx.vout[0], enote_scan_info_protocol.address_spend_pubkey),
|
||||
error::wallet_internal_error,
|
||||
"failed to retrieve origin TX address spend pubkey");
|
||||
enote_scan_info_protocol.amount = tx.vout[local_output_index].amount;
|
||||
enote_scan_info_protocol.amount_blinding_factor = rct::I;
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_asset_type(tx.vout[local_output_index], enote_scan_info_protocol.asset_type),
|
||||
error::wallet_internal_error,
|
||||
"failed to retrieve output asset type");
|
||||
enote_scan_info_protocol.main_tx_pubkey_index = 0;
|
||||
enote_scan_info_protocol.payment_id = crypto::null_hash;
|
||||
enote_scan_info_protocol.subaddr_index = carrot::subaddress_index_extended{{td_origin.m_subaddr_index.major,td_origin.m_subaddr_index.minor}};
|
||||
|
||||
} else if (td_origin.m_tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// Check the amount
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin.m_tx.amount_burnt != tx.vout[local_output_index].amount,
|
||||
error::wallet_internal_error,
|
||||
"AUDIT TX error - payout " + print_money(tx.vout[local_output_index].amount) +
|
||||
" does not match audited amount " + print_money(td_origin.m_tx.amount_burnt));
|
||||
|
||||
// Populate the dummy enote_scan_info struct
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(td_origin.m_tx.vout[0], enote_scan_info_protocol.address_spend_pubkey),
|
||||
error::wallet_internal_error,
|
||||
"failed to retrieve origin TX address spend pubkey");
|
||||
enote_scan_info_protocol.amount = tx.vout[local_output_index].amount;
|
||||
enote_scan_info_protocol.amount_blinding_factor = rct::I;
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_asset_type(tx.vout[local_output_index], enote_scan_info_protocol.asset_type),
|
||||
error::wallet_internal_error,
|
||||
"failed to retrieve output asset type");
|
||||
enote_scan_info_protocol.main_tx_pubkey_index = 0;
|
||||
enote_scan_info_protocol.payment_id = crypto::null_hash;
|
||||
enote_scan_info_protocol.subaddr_index = carrot::subaddress_index_extended{{td_origin.m_subaddr_index.major,td_origin.m_subaddr_index.minor}};
|
||||
|
||||
} else {
|
||||
|
||||
// Should never happen - only STAKE and AUDIT should pay out in a PROTOCOL transaction
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Get the output key for the change entry
|
||||
crypto::public_key pk_locked_coins = crypto::null_pkey;
|
||||
THROW_WALLET_EXCEPTION_IF(!get_output_public_key(td_origin.m_tx.vout[td_origin.m_internal_output_index], pk_locked_coins),
|
||||
error::wallet_internal_error,
|
||||
"Failed to get output public key for locked coins");
|
||||
|
||||
// At this point, we need to clear the "locked coins" count, because otherwise we will be counting yield stakes twice in our balance
|
||||
//THROW_WALLET_EXCEPTION_IF(!m_locked_coins.erase(pk_locked_coins), error::wallet_internal_error, "Failed to remove protocol_tx entry from m_locked_coins");
|
||||
if (!m_locked_coins.erase(pk_locked_coins)) {
|
||||
LOG_ERROR("Failed to remove protocol_tx entry from m_locked_coins - possible duplicate output key detected");
|
||||
}
|
||||
} else {
|
||||
// Check for return_payment
|
||||
if (m_salvium_txs.count(enote_scan_info_local->address_spend_pubkey)) {
|
||||
// Must be a return payment
|
||||
td_origin_idx = m_salvium_txs[enote_scan_info_local->address_spend_pubkey];
|
||||
}
|
||||
}
|
||||
|
||||
const auto &enote_scan_info = (is_protocol) ? enote_scan_info_protocol : enote_scan_info_local;
|
||||
|
||||
// check for burning bug
|
||||
const auto ot_it = m_pub_keys.find(onetime_address);
|
||||
const transfer_details *burning_td = ot_it != m_pub_keys.cend() ? &m_transfers.at(ot_it->second) : nullptr;
|
||||
const bool should_treat_as_burned = burning_td &&
|
||||
(burning_td->amount() >= enote_scan_info->amount || burning_td->m_spent)
|
||||
;
|
||||
(burning_td->amount() >= enote_scan_info->amount || burning_td->m_spent);
|
||||
if (should_treat_as_burned)
|
||||
{
|
||||
// We already have an older received transfer with a greater-than-or-equal amount
|
||||
LOG_ERROR("Public key " << epee::string_tools::pod_to_hex(ot_it->first)
|
||||
<< " from received " << print_money(enote_scan_info->amount) << " output already exists with "
|
||||
<< (burning_td->m_spent ? "spent" : "unspent") << " "
|
||||
<< print_money(burning_td->amount()) << " in tx " << burning_td->m_txid << ", received output ignored");
|
||||
<< " from received " << print_money(enote_scan_info->amount) << " output already exists with "
|
||||
<< (burning_td->m_spent ? "spent" : "unspent") << " "
|
||||
<< print_money(burning_td->amount()) << " in tx " << burning_td->m_txid << ", received output ignored");
|
||||
continue;
|
||||
}
|
||||
else if (burning_td)
|
||||
@@ -2680,8 +2587,14 @@ void wallet2::process_new_scanned_transaction(
|
||||
const rct::xmr_amount extra_received_money = enote_scan_info->amount - (burning_td ? burning_td->amount() : 0);
|
||||
const cryptonote::subaddress_index subaddr_index_cn{
|
||||
enote_scan_info->subaddr_index->index.major, enote_scan_info->subaddr_index->index.minor};
|
||||
tx_money_got_in_outs[subaddr_index_cn][enote_scan_info->asset_type] += extra_received_money;
|
||||
tx_amounts_individual_outs[subaddr_index_cn].push_back(extra_received_money);
|
||||
|
||||
// we have to save even the 0 amount enotes since we need to save their one time addresses
|
||||
// for some protocol txs.
|
||||
//if (enote_scan_info->amount > 0)
|
||||
{
|
||||
tx_money_got_in_outs[subaddr_index_cn][enote_scan_info->asset_type] += extra_received_money;
|
||||
tx_amounts_individual_outs[subaddr_index_cn].push_back(std::make_tuple(extra_received_money, onetime_address));
|
||||
}
|
||||
|
||||
// set payment id
|
||||
const bool ignore_long_pid = block_version >= IGNORE_LONG_PAYMENT_ID_FROM_BLOCK_VERSION;
|
||||
@@ -2707,10 +2620,6 @@ void wallet2::process_new_scanned_transaction(
|
||||
if (pool)
|
||||
continue;
|
||||
|
||||
// expand subaddress table if applicable
|
||||
if (should_expand(subaddr_index_cn))
|
||||
expand_subaddresses(subaddr_index_cn);
|
||||
|
||||
// update m_transfers view-incoming scan info, and default values
|
||||
transfer_details& td = tools::add_element(m_transfers);
|
||||
td.m_block_height = height;
|
||||
@@ -2727,47 +2636,12 @@ void wallet2::process_new_scanned_transaction(
|
||||
td.m_recovered_spend_pubkey = enote_scan_info->address_spend_pubkey;
|
||||
td.m_rct = tx.version >= 2;
|
||||
td.m_frozen = false;
|
||||
set_unspent(m_transfers.size() - 1);
|
||||
td.m_td_origin_idx = td_origin_idx;
|
||||
td.m_td_origin_idx = m_salvium_txs.find(enote_scan_info->address_spend_pubkey) != m_salvium_txs.end() ?
|
||||
m_salvium_txs.at(enote_scan_info->address_spend_pubkey) : std::numeric_limits<uint64_t>::max();
|
||||
|
||||
// update m_transfers key image values
|
||||
if (td_origin_idx != (uint64_t)-1) {
|
||||
|
||||
// Return payment received - rebuild the correct key image
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin_idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate return_payment TX origin in m_transfers");
|
||||
const transfer_details &td_origin = m_transfers[td_origin_idx];
|
||||
hw::device &hwdev = m_account.get_device();
|
||||
hw::reset_mode rst(hwdev);
|
||||
hwdev.set_mode(hw::device::TRANSACTION_PARSE);
|
||||
const crypto::public_key tx_public_key = get_tx_pub_key_from_extra(tx);
|
||||
const std::vector<crypto::public_key> additional_tx_public_keys = get_additional_tx_pub_keys_from_extra(tx);
|
||||
keypair in_ephemeral;
|
||||
crypto::key_image ki;
|
||||
origin_data origin_tx_data;
|
||||
origin_tx_data.tx_pub_key = get_tx_pub_key_from_extra(td_origin.m_tx);
|
||||
origin_tx_data.output_index = td_origin.m_internal_output_index;
|
||||
origin_tx_data.tx_type = td_origin.m_tx.type;
|
||||
rct::salvium_input_data_t sid;
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::generate_key_image_helper(m_account.get_keys(),
|
||||
m_subaddresses,
|
||||
onetime_address,
|
||||
tx_public_key,
|
||||
additional_tx_public_keys,
|
||||
local_output_index,
|
||||
in_ephemeral,
|
||||
ki,
|
||||
hwdev,
|
||||
true,
|
||||
origin_tx_data,
|
||||
sid),
|
||||
error::wallet_internal_error,
|
||||
"failed to obtain key image for protocol_tx output");
|
||||
td.m_key_image_known = true;
|
||||
td.m_key_image = ki;
|
||||
} else {
|
||||
td.m_key_image_known = bool(output_key_images[local_output_index]);
|
||||
td.m_key_image = output_key_images[local_output_index].value_or(crypto::key_image{});
|
||||
}
|
||||
td.m_key_image_known = bool(output_key_images[local_output_index]);
|
||||
td.m_key_image = output_key_images[local_output_index].value_or(crypto::key_image{});
|
||||
if (!td.m_key_image_known)
|
||||
{
|
||||
// we might have cold signed, and have a mapping to key images
|
||||
@@ -2778,11 +2652,12 @@ void wallet2::process_new_scanned_transaction(
|
||||
td.m_key_image_known = true;
|
||||
}
|
||||
}
|
||||
if (!td.m_key_image_known && is_protocol)
|
||||
|
||||
// override the key image for pre-carrot PROTOCOL/RETURN tx outputs.
|
||||
if (!enote_scan_info->is_carrot && td.m_td_origin_idx != std::numeric_limits<uint64_t>::max())
|
||||
{
|
||||
// We need to manually create the key image data
|
||||
THROW_WALLET_EXCEPTION_IF(td_origin_idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate protocol TX origin in m_transfers");
|
||||
const transfer_details &td_origin = m_transfers[td_origin_idx];
|
||||
THROW_WALLET_EXCEPTION_IF(td.m_td_origin_idx >= get_num_transfer_details(), error::wallet_internal_error, "cannot locate return_payment TX origin in m_transfers");
|
||||
const transfer_details &td_origin = m_transfers[td.m_td_origin_idx];
|
||||
hw::device &hwdev = m_account.get_device();
|
||||
hw::reset_mode rst(hwdev);
|
||||
hwdev.set_mode(hw::device::TRANSACTION_PARSE);
|
||||
@@ -2795,26 +2670,30 @@ void wallet2::process_new_scanned_transaction(
|
||||
origin_tx_data.output_index = td_origin.m_internal_output_index;
|
||||
origin_tx_data.tx_type = td_origin.m_tx.type;
|
||||
rct::salvium_input_data_t sid;
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::generate_key_image_helper(m_account.get_keys(),
|
||||
m_subaddresses,
|
||||
onetime_address,
|
||||
tx_public_key,
|
||||
additional_tx_public_keys,
|
||||
local_output_index,
|
||||
in_ephemeral,
|
||||
ki,
|
||||
hwdev,
|
||||
true,
|
||||
origin_tx_data,
|
||||
sid),
|
||||
error::wallet_internal_error,
|
||||
"failed to obtain key image for protocol_tx output");
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::generate_key_image_helper(
|
||||
m_account.get_keys(),
|
||||
m_account.get_subaddress_map_cn(),
|
||||
onetime_address,
|
||||
tx_public_key,
|
||||
additional_tx_public_keys,
|
||||
local_output_index,
|
||||
in_ephemeral,
|
||||
ki,
|
||||
hwdev,
|
||||
true,
|
||||
origin_tx_data,
|
||||
sid),
|
||||
error::wallet_internal_error,
|
||||
"failed to obtain key image for protocol_tx output"
|
||||
);
|
||||
td.m_key_image_known = true;
|
||||
td.m_key_image = ki;
|
||||
}
|
||||
td.m_key_image_request = m_watch_only; // for view wallets, that flag means "we want to request it"
|
||||
td.m_key_image_partial = m_multisig;
|
||||
|
||||
set_unspent(m_transfers.size() - 1);
|
||||
|
||||
// update m_key_images, m_pub_keys, and output_tracker_cache
|
||||
if (td.m_key_image_known)
|
||||
m_key_images[td.m_key_image] = m_transfers.size() - 1;
|
||||
@@ -2834,44 +2713,9 @@ void wallet2::process_new_scanned_transaction(
|
||||
update_multisig_rescan_info(*m_multisig_rescan_k, *m_multisig_rescan_info, m_transfers.size() - 1);
|
||||
}
|
||||
|
||||
// Check for Salvium-specific logic
|
||||
if (tx.type == cryptonote::transaction_type::TRANSFER) {
|
||||
|
||||
// Store the potential return details for a pre-Carrot return_payment
|
||||
// We might store garbage entries here occasionally, but they shouldn't impact performance significantly
|
||||
crypto::public_key P_change = crypto::null_pkey;
|
||||
size_t change_idx = local_output_index;
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(tx.vout[change_idx], P_change), error::wallet_internal_error, "Failed to get output public key");
|
||||
m_subaddresses[P_change] = subaddr_index_cn;
|
||||
m_salvium_txs.insert({P_change, m_transfers.size()-1});
|
||||
|
||||
} else if (tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
|
||||
// The CONVERT/STAKE/AUDIT TX was created by us - therefore we need to expect an output in the PROTOCOL_TX
|
||||
// It could be a refund, an audit, or a conversion
|
||||
THROW_WALLET_EXCEPTION_IF(tx.vout.size() != 1, error::wallet_internal_error, "Incorrect number of outputs from CONVERT/STAKE/AUDIT TX");
|
||||
|
||||
// Add the change output_public_key to the list of subaddresses to check
|
||||
crypto::public_key P_change = crypto::null_pkey;
|
||||
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(tx.vout[0], P_change), error::wallet_internal_error, "Failed to get change output public key");
|
||||
m_subaddresses[P_change] = subaddr_index_cn;//tx_scan_info[o].received->index;//{0,0};
|
||||
if (block_version >= HF_VERSION_ENABLE_N_OUTS)
|
||||
m_salvium_txs.insert({tx.return_address_list[local_output_index], m_transfers.size()-1});
|
||||
else
|
||||
m_salvium_txs.insert({tx.return_address, m_transfers.size()-1});
|
||||
|
||||
if (tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
|
||||
// Additionally, with STAKE and AUDIT TXs, we need to update our "balance staked" subtotal, because otherwise our balance is out by the staked coins until they mature!
|
||||
// SRCG: must remember to deduct the number of staked coins when they mature!!
|
||||
LOG_PRINT_L1("***** STAKED/AUDITED COINS : " << tx.amount_burnt << " *****");
|
||||
m_locked_coins.insert({P_change, {0, tx.amount_burnt, tx.source_asset_type}});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// money received callbacks
|
||||
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
|
||||
if (!ignore_callbacks && 0 != m_callback)
|
||||
if (!ignore_callbacks && 0 != m_callback && td.m_amount > 0)
|
||||
m_callback->on_money_received(height, txid, tx, td.m_amount, td.asset_type, 0, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time, td.m_td_origin_idx);
|
||||
}
|
||||
|
||||
@@ -3002,8 +2846,29 @@ void wallet2::process_new_scanned_transaction(
|
||||
{
|
||||
if (subaddr_account && i->first.major == *subaddr_account)
|
||||
{
|
||||
// tx_amounts_individual_outs.erase(i->first);
|
||||
// i = tx_money_got_in_outs.erase(i);
|
||||
// save the change output key in our subaddress_map, so we can receive money to it later
|
||||
// from protocol or return txs
|
||||
for (const auto &entry: tx_amounts_individual_outs[i->first]) {
|
||||
const crypto::public_key &onetime_address = std::get<1>(entry);
|
||||
carrot::AddressDeriveType derive_type;
|
||||
if (use_fork_rules(HF_VERSION_CARROT, 0)) {
|
||||
derive_type = carrot::AddressDeriveType::Carrot;
|
||||
} else {
|
||||
derive_type = carrot::AddressDeriveType::PreCarrot;
|
||||
}
|
||||
const carrot::subaddress_index_extended subaddr_ext = {i->first.major, i->first.minor, derive_type, true};
|
||||
// save to m_subaddresses as well, so that we can populate account subaddress map
|
||||
// when we open the wallet first time.
|
||||
if (derive_type == carrot::AddressDeriveType::PreCarrot)
|
||||
m_subaddresses_extended[onetime_address] = subaddr_ext;
|
||||
|
||||
// update m_salvium_txs
|
||||
m_salvium_txs.insert({onetime_address, m_transfers.size()-1});
|
||||
}
|
||||
|
||||
// delete change output from amounts
|
||||
tx_amounts_individual_outs.erase(i->first);
|
||||
|
||||
// delete individual change asset output
|
||||
for (auto assets_it = i->second.begin(); assets_it != i->second.end();) {
|
||||
if (assets_it->first == source_asset)
|
||||
@@ -3029,12 +2894,16 @@ void wallet2::process_new_scanned_transaction(
|
||||
{
|
||||
for (const auto& j : i.second)
|
||||
{
|
||||
amounts_container amounts;
|
||||
for (const auto& entry: tx_amounts_individual_outs[i.first]) {
|
||||
amounts.push_back(std::get<0>(entry));
|
||||
}
|
||||
payment_details payment;
|
||||
payment.m_tx_hash = txid;
|
||||
payment.m_fee = fee;
|
||||
payment.m_asset_type = j.first;
|
||||
payment.m_amount = j.second;
|
||||
payment.m_amounts = tx_amounts_individual_outs[i.first];
|
||||
payment.m_amounts = amounts;
|
||||
payment.m_block_height = height;
|
||||
payment.m_unlock_time = tx.unlock_time;
|
||||
payment.m_timestamp = ts;
|
||||
@@ -3133,6 +3002,7 @@ void wallet2::process_outgoing(const crypto::hash &txid, const cryptonote::trans
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool wallet2::should_skip_block(const cryptonote::block &b, uint64_t height) const
|
||||
{
|
||||
if (height == 0) return false;
|
||||
// seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup
|
||||
return !(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height && height >= m_skip_to_height);
|
||||
}
|
||||
@@ -3149,7 +3019,11 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b,
|
||||
THROW_WALLET_EXCEPTION_IF(bche.txs.size() + 2 != parsed_block.o_indices.indices.size(), error::wallet_internal_error,
|
||||
"block transactions=" + std::to_string(bche.txs.size()) +
|
||||
" not match with daemon response size=" + std::to_string(parsed_block.o_indices.indices.size()));
|
||||
|
||||
|
||||
if (height == 0) {
|
||||
m_blockchain.clear();
|
||||
}
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(height != m_blockchain.size(), error::wallet_internal_error,
|
||||
"New blockchain entry mismatch: block height " + std::to_string(height) +
|
||||
" is not the expected next height " + std::to_string(m_blockchain.size()));
|
||||
@@ -3470,25 +3344,28 @@ void wallet2::process_parsed_blocks(const uint64_t start_height, const std::vect
|
||||
hw::reset_mode rst(hwdev);
|
||||
hwdev.set_mode(hw::device::TRANSACTION_PARSE);
|
||||
|
||||
// Create a thread-safe keystore instance to allow detection of `STAKE`, `AUDIT` and `RETURN_PAYMENT` TX outputs
|
||||
tools::keystore keystore(m_subaddresses);
|
||||
|
||||
// define view-incoming scan and key image derivation job
|
||||
std::vector<std::optional<wallet::enote_view_incoming_scan_info_t>> enote_scan_infos(num_tx_outputs);
|
||||
std::vector<std::optional<crypto::key_image>> output_key_images(num_tx_outputs);
|
||||
bool password_failure = false;
|
||||
auto tx_scan_job = [this, &enote_scan_infos, &output_key_images, &password_failure, &keystore]
|
||||
auto tx_scan_job = [this, &enote_scan_infos, &output_key_images, &password_failure]
|
||||
(const cryptonote::transaction &tx, size_t tx_output_idx)
|
||||
{
|
||||
if (tx.vout.empty())
|
||||
{
|
||||
MWARNING("Skipping tx without any outputs: " << get_transaction_hash(tx) << ", height: " << m_blockchain.size());
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t output_span_end = tx_output_idx + tx.vout.size();
|
||||
if (output_span_end > enote_scan_infos.size() || output_span_end > output_key_images.size())
|
||||
{
|
||||
LOG_ERROR("BUG: tx scan worker output index out of bounds, skipping...");
|
||||
return;
|
||||
}
|
||||
|
||||
wallet::view_incoming_scan_transaction(tx,
|
||||
this->m_account.get_keys(),
|
||||
keystore,
|
||||
this->m_account,
|
||||
{&enote_scan_infos[0] + tx_output_idx, tx.vout.size()});
|
||||
|
||||
// if view-incoming scan was successful, try deriving the key image
|
||||
@@ -3505,11 +3382,25 @@ void wallet2::process_parsed_blocks(const uint64_t start_height, const std::vect
|
||||
size_t i = 0;
|
||||
size_t tx_output_idx = 0;
|
||||
while (i < blocks.size()) {
|
||||
/*
|
||||
if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
|
||||
tx_scan_job(par_blk.block.miner_tx, tx_output_idx);
|
||||
tx_output_idx += par_blk.block.miner_tx.vout.size();
|
||||
if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
|
||||
tx_scan_job(par_blk.block.protocol_tx, tx_output_idx);
|
||||
tx_output_idx += par_blk.block.protocol_tx.vout.size();
|
||||
for (const cryptonote::transaction &tx : par_blk.txes)
|
||||
{
|
||||
if (!skip_scan_for_this_block)
|
||||
tx_scan_job(tx, tx_output_idx);
|
||||
tx_output_idx += tx.vout.size();
|
||||
*/
|
||||
tools::threadpool::waiter scan_blocks_waiter(tpool);
|
||||
for (size_t j = 0; j < 10; ++j)
|
||||
{
|
||||
const parsed_block &par_blk = parsed_blocks.at(i);
|
||||
const std::uint64_t height = start_height + i;
|
||||
if (i+j >= blocks.size()) break;
|
||||
const parsed_block &par_blk = parsed_blocks.at(i+j);
|
||||
const std::uint64_t height = start_height + i + j;
|
||||
const bool skip_scan_for_this_block = should_skip_block(par_blk.block, height);
|
||||
if (!skip_scan_for_this_block && m_refresh_type != RefreshNoCoinbase)
|
||||
tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(par_blk.block.miner_tx), tx_output_idx));
|
||||
@@ -3523,13 +3414,13 @@ void wallet2::process_parsed_blocks(const uint64_t start_height, const std::vect
|
||||
tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(tx), tx_output_idx));
|
||||
tx_output_idx += tx.vout.size();
|
||||
}
|
||||
if (++i >= blocks.size()) break;
|
||||
}
|
||||
if (!scan_blocks_waiter.wait())
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(password_failure, error::password_needed);
|
||||
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Unrecognized exception in enote scanning threadpool");
|
||||
}
|
||||
i+=10;
|
||||
}
|
||||
|
||||
// Start processing blockchain entries with scanned outputs
|
||||
@@ -3549,7 +3440,7 @@ void wallet2::process_parsed_blocks(const uint64_t start_height, const std::vect
|
||||
const epee::span<const std::optional<crypto::key_image>> output_key_images_span(
|
||||
output_key_images.data() + tx_output_idx, n_block_outputs);
|
||||
|
||||
if(current_index >= m_blockchain.size())
|
||||
if(!current_index || current_index >= m_blockchain.size())
|
||||
{
|
||||
process_new_blockchain_entry(bl, blocks[i], parsed_blocks[i], bl_id, current_index, enote_scan_infos_span, output_key_images_span, output_tracker_cache);
|
||||
++blocks_added;
|
||||
@@ -5521,13 +5412,8 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
|
||||
|
||||
if (r)
|
||||
{
|
||||
// Generate the Carrot keys here
|
||||
m_carrot_account.legacy_acb = m_account;
|
||||
m_carrot_account.generate();
|
||||
}
|
||||
|
||||
if (r)
|
||||
{
|
||||
m_account.set_carrot_keys();
|
||||
|
||||
if (!m_is_background_wallet)
|
||||
setup_keys(password);
|
||||
else
|
||||
@@ -6710,6 +6596,17 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
|
||||
|
||||
if (get_num_subaddress_accounts() == 0)
|
||||
add_subaddress_account(tr("Primary account"));
|
||||
m_account.insert_subaddresses(m_subaddresses_extended);
|
||||
if (!m_subaddresses.empty())
|
||||
{
|
||||
// if we have subaddresses, we need to insert them into the account
|
||||
for (const auto &subaddress : m_subaddresses)
|
||||
m_account.insert_subaddresses(
|
||||
// TODO: we assume none of these subaddresses are return tx subaddresses
|
||||
{{subaddress.first, {{subaddress.second.major, subaddress.second.minor}, carrot::AddressDeriveType::PreCarrot, false}}}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
@@ -6915,9 +6812,10 @@ void wallet2::process_background_cache_on_open()
|
||||
background_w2->m_background_sync_type = m_background_sync_type;
|
||||
background_w2->m_custom_background_key = m_custom_background_key;
|
||||
|
||||
cryptonote::account_base account = m_account;
|
||||
account.forget_spend_key();
|
||||
background_w2->m_account = account;
|
||||
// TODO: uncommet this block
|
||||
// carrot::carrot_and_legacy_account account = m_account;
|
||||
// account.forget_spend_key();
|
||||
// background_w2->m_account = account;
|
||||
|
||||
// Load background cache from file
|
||||
background_w2->clear();
|
||||
@@ -10532,7 +10430,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
|
||||
std::vector<std::pair<std::string, std::string>> circ_amounts;
|
||||
THROW_WALLET_EXCEPTION_IF(!get_circulating_supply(circ_amounts), error::wallet_internal_error, "Failed to get circulating supply");
|
||||
// make a normal tx
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(a_keys/*m_account.get_keys()*/, m_subaddresses, sources, splitted_dsts, hf_version, source_asset, dest_asset, tx_type, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
|
||||
bool r = cryptonote::construct_tx_and_get_tx_key(a_keys/*m_account.get_keys()*/, m_account.get_subaddress_map_cn(), sources, splitted_dsts, hf_version, source_asset, dest_asset, tx_type, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags);
|
||||
LOG_PRINT_L2("constructed tx, r="<<r);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_nettype);
|
||||
}
|
||||
@@ -10839,7 +10737,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
|
||||
const bool do_carrot_tx_construction = use_fork_rules(HF_VERSION_CARROT);
|
||||
if (do_carrot_tx_construction)
|
||||
{
|
||||
const auto tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_transfer(*this, dsts, priority, extra, subaddr_account, subaddr_indices, subtract_fee_from_outputs);
|
||||
const auto tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_transfer(*this, dsts, priority, extra, tx_type, subaddr_account, subaddr_indices, subtract_fee_from_outputs);
|
||||
std::vector<pending_tx> ptx_vector;
|
||||
ptx_vector.reserve(tx_proposals.size());
|
||||
for (const auto &tx_proposal : tx_proposals)
|
||||
@@ -11675,7 +11573,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
const bool do_carrot_tx_construction = use_fork_rules(HF_VERSION_CARROT);
|
||||
if (do_carrot_tx_construction)
|
||||
{
|
||||
const auto tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep_all(*this, below, address, is_subaddress, outputs, priority, extra, subaddr_account, subaddr_indices);
|
||||
const auto tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep_all(*this, below, address, is_subaddress, outputs, priority, extra, tx_type, subaddr_account, subaddr_indices);
|
||||
std::vector<pending_tx> ptx_vector;
|
||||
ptx_vector.reserve(tx_proposals.size());
|
||||
// TODO: use CLSAGS here..
|
||||
@@ -11761,12 +11659,12 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
return create_transactions_from(address, tx_type, asset_type, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
|
||||
}
|
||||
|
||||
std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
|
||||
std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, const cryptonote::transaction_type tx_type, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra)
|
||||
{
|
||||
const bool do_carrot_tx_construction = use_fork_rules(HF_VERSION_CARROT);
|
||||
if (do_carrot_tx_construction)
|
||||
{
|
||||
const auto tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(*this, {ki}, address, is_subaddress, outputs, priority, extra);
|
||||
const auto tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(*this, {ki}, address, is_subaddress, outputs, priority, extra, tx_type);
|
||||
std::vector<pending_tx> ptx_vector;
|
||||
ptx_vector.reserve(tx_proposals.size());
|
||||
// TODO: use CLSAGS here..
|
||||
@@ -11803,7 +11701,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
|
||||
THROW_WALLET_EXCEPTION_IF(idx >= get_num_transfer_details(), error::wallet_internal_error, tr("cannot locate return_payment origin index in m_transfers"));
|
||||
const transfer_details& td_origin = get_transfer_details(idx);
|
||||
const std::string asset_type = td_origin.m_tx.source_asset_type;
|
||||
bool is_subaddress = true;
|
||||
bool is_subaddress = false;
|
||||
size_t outputs = 1;
|
||||
std::vector<size_t> unused_dust_indices = {};
|
||||
size_t fake_outs_count = get_min_ring_size() - 1; // Use the default ring size
|
||||
@@ -11818,6 +11716,111 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
|
||||
THROW_WALLET_EXCEPTION_IF(td.m_txid != td_origin.m_txid, error::wallet_internal_error, tr("TX hashes do not match for inputs to return_payment"));
|
||||
THROW_WALLET_EXCEPTION_IF(td.asset_type != td_origin.asset_type, error::wallet_internal_error, tr("TX asset_type values do not match for inputs to return_payment"));
|
||||
}
|
||||
|
||||
const bool do_carrot_tx_construction = use_fork_rules(HF_VERSION_CARROT);
|
||||
if (do_carrot_tx_construction)
|
||||
{
|
||||
// calculate the return address
|
||||
// 1. parse tx extra
|
||||
std::vector<crypto::public_key> main_tx_ephemeral_pubkeys;
|
||||
std::vector<crypto::public_key> additional_tx_ephemeral_pubkeys;
|
||||
cryptonote::blobdata tx_extra_nonce;
|
||||
if (!wallet::parse_tx_extra_for_scanning(td_origin.m_tx.extra,
|
||||
td_origin.m_tx.vout.size(),
|
||||
main_tx_ephemeral_pubkeys,
|
||||
additional_tx_ephemeral_pubkeys,
|
||||
tx_extra_nonce))
|
||||
MWARNING("Return transaction extra has unsupported format: ");
|
||||
|
||||
THROW_WALLET_EXCEPTION_IF(main_tx_ephemeral_pubkeys.empty() && additional_tx_ephemeral_pubkeys.empty(), error::wallet_internal_error,
|
||||
"Transaction missing ephemeral pubkeys");
|
||||
const bool is_carrot = carrot::is_carrot_transaction_v1(td_origin.m_tx);
|
||||
THROW_WALLET_EXCEPTION_IF(!is_carrot, error::wallet_internal_error,
|
||||
"Return payment is only supported for Carrot transactions");
|
||||
|
||||
// 2. perform ECDH derivations
|
||||
std::vector<crypto::key_derivation> main_derivations;
|
||||
std::vector<crypto::key_derivation> additional_derivations;
|
||||
wallet::perform_ecdh_derivations(
|
||||
epee::to_span(main_tx_ephemeral_pubkeys),
|
||||
epee::to_span(additional_tx_ephemeral_pubkeys),
|
||||
m_account.get_keys().k_view_incoming,
|
||||
m_account.get_keys().get_device(),
|
||||
is_carrot,
|
||||
main_derivations,
|
||||
additional_derivations
|
||||
);
|
||||
|
||||
// 3. input context
|
||||
carrot::input_context_t input_context = carrot::gen_input_context();
|
||||
if (td_origin.m_tx.vin[0].type() == typeid(cryptonote::txin_to_key)) {
|
||||
input_context = carrot::make_carrot_input_context(boost::get<cryptonote::txin_to_key>(td_origin.m_tx.vin[0]).k_image);
|
||||
} else if (td_origin.m_tx.vin[0].type() == typeid(cryptonote::txin_gen)) {
|
||||
input_context = carrot::make_carrot_input_context_coinbase(boost::get<cryptonote::txin_gen>(td_origin.m_tx.vin[0]).height);
|
||||
} else {
|
||||
THROW_WALLET_EXCEPTION_IF(true, error::wallet_internal_error, "Unsupported input type for return_payment");
|
||||
}
|
||||
const mx25519_pubkey origin_tx_shared_secret_unctx = carrot::raw_byte_convert<mx25519_pubkey>(main_derivations[0]);
|
||||
|
||||
// 4. compute m_return
|
||||
crypto::public_key output_key;
|
||||
carrot::encrypted_return_pubkey_t m_return;
|
||||
THROW_WALLET_EXCEPTION_IF(
|
||||
!cryptonote::get_output_public_key(td_origin.m_tx.vout[td_origin.m_internal_output_index], output_key),
|
||||
error::wallet_internal_error,
|
||||
"Failed to identify output key"
|
||||
);
|
||||
carrot::make_sparc_return_pubkey_encryption_mask(
|
||||
origin_tx_shared_secret_unctx.data,
|
||||
input_context,
|
||||
output_key,
|
||||
m_return
|
||||
);
|
||||
|
||||
// 5. compute K_return from m_return
|
||||
carrot::encrypted_return_pubkey_t K_return;
|
||||
crypto::public_key return_pub;
|
||||
std::memcpy(
|
||||
K_return.bytes,
|
||||
td_origin.m_tx.return_address_list[td_origin.m_internal_output_index].data,
|
||||
sizeof(carrot::encrypted_return_pubkey_t)
|
||||
);
|
||||
K_return = K_return ^ m_return;
|
||||
static_assert(sizeof(K_return.bytes) == sizeof(return_pub.data), "Size mismatch");
|
||||
std::memcpy(return_pub.data, K_return.bytes, sizeof(carrot::encrypted_return_pubkey_t));
|
||||
|
||||
// 6. compute the change index
|
||||
crypto::secret_key z_i;
|
||||
derivation_to_scalar(main_derivations[0], td_origin.m_internal_output_index, z_i);
|
||||
struct {
|
||||
char domain_separator[8];
|
||||
crypto::secret_key output_index_key;
|
||||
} buf;
|
||||
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
|
||||
std::strncpy(buf.domain_separator, "CHG_IDX", 8);
|
||||
std::memcpy(buf.output_index_key.data, z_i.data, sizeof(crypto::secret_key));
|
||||
uint8_t eci_data = td_origin.m_tx.return_address_change_mask[td_origin.m_internal_output_index];
|
||||
crypto::secret_key eci_out;
|
||||
keccak((uint8_t *)&buf, sizeof(buf), (uint8_t*)&eci_out, sizeof(eci_out));
|
||||
uint8_t change_index = eci_data ^ eci_out.data[0];
|
||||
|
||||
crypto::public_key change_key;
|
||||
THROW_WALLET_EXCEPTION_IF(
|
||||
!cryptonote::get_output_public_key(td_origin.m_tx.vout[change_index], change_key),
|
||||
error::wallet_internal_error,
|
||||
"Failed to identify change output"
|
||||
);
|
||||
|
||||
// 7. Make a destination address for the return
|
||||
cryptonote::account_public_address address;
|
||||
address.m_spend_public_key = change_key;
|
||||
address.m_view_public_key = return_pub;
|
||||
|
||||
return create_transactions_from(address, cryptonote::transaction_type::RETURN, asset_type, is_subaddress, outputs, transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra);
|
||||
}
|
||||
|
||||
// pre-carrot return payment construction uses subaddress true
|
||||
is_subaddress = true;
|
||||
|
||||
// To return a payment, we need to know the y value to process the F value
|
||||
// ...but the y value is calculated differently depending on the original TX
|
||||
@@ -11941,12 +11944,11 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton
|
||||
for (const size_t transfer_idx : unused_dust_indices)
|
||||
input_key_images.push_back(m_transfers.at(transfer_idx).m_key_image);
|
||||
|
||||
const auto tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(*this, input_key_images, address, is_subaddress, outputs, priority, extra);
|
||||
const auto tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(*this, input_key_images, address, is_subaddress, outputs, priority, extra, tx_type);
|
||||
std::vector<pending_tx> ptx_vector;
|
||||
ptx_vector.reserve(tx_proposals.size());
|
||||
// TODO: use CLSAGS here..
|
||||
// for (const auto &tx_proposal : tx_proposals)
|
||||
// ptx_vector.push_back(tools::wallet::finalize_all_proofs_from_transfer_details_as_pending_tx(tx_proposal, *this));
|
||||
for (const auto &tx_proposal : tx_proposals)
|
||||
ptx_vector.push_back(tools::wallet::finalize_all_proofs_from_transfer_details_as_pending_tx(tx_proposal, *this));
|
||||
return ptx_vector;
|
||||
}
|
||||
|
||||
@@ -12888,9 +12890,9 @@ void wallet2::check_tx_key_helper(const cryptonote::transaction &tx, const crypt
|
||||
received = 0;
|
||||
|
||||
const auto enote_scan_infos = wallet::view_incoming_scan_transaction_as_sender(tx,
|
||||
{&derivation, 1},
|
||||
epee::to_span(additional_derivations),
|
||||
address);
|
||||
{&derivation, 1},
|
||||
epee::to_span(additional_derivations),
|
||||
address);
|
||||
|
||||
for (const auto &enote_scan_info : enote_scan_infos)
|
||||
if (enote_scan_info && enote_scan_info->address_spend_pubkey == address.m_spend_public_key)
|
||||
@@ -13541,7 +13543,7 @@ bool wallet2::check_reserve_proof(const cryptonote::account_public_address &addr
|
||||
crypto::secret_key shared_secret;
|
||||
crypto::derivation_to_scalar(derivation, proof.index_in_tx, shared_secret);
|
||||
rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[proof.index_in_tx];
|
||||
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), 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::RCTTypeSalviumOne);
|
||||
rct::ecdhDecode(ecdh_info, rct::sk2rct(shared_secret), 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);
|
||||
amount = rct::h2d(ecdh_info.amount);
|
||||
}
|
||||
total += amount;
|
||||
@@ -13891,8 +13893,6 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
|
||||
error::wallet_internal_error,
|
||||
"get_tx_pub_key_from_received_outs is not relevant for Carrot txs");
|
||||
|
||||
tools::keystore subaddress_keystore(m_subaddresses);
|
||||
|
||||
const auto enote_scan_info = wallet::view_incoming_scan_enote_from_prefix(
|
||||
td.m_tx,
|
||||
td.amount(),
|
||||
@@ -13900,7 +13900,7 @@ crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::walle
|
||||
td.m_internal_output_index,
|
||||
m_account_public_address,
|
||||
m_account.get_keys().m_view_secret_key,
|
||||
subaddress_keystore,
|
||||
m_account,
|
||||
m_account.get_device());
|
||||
|
||||
const size_t main_tx_pubkey_index = enote_scan_info ? enote_scan_info->main_tx_pubkey_index : 0;
|
||||
@@ -14221,7 +14221,6 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||
PERF_TIMER_START(import_key_images_F);
|
||||
auto spent_txid = spent_txids.begin();
|
||||
auto it = spent_txids.begin();
|
||||
tools::keystore keystore(m_subaddresses);
|
||||
for (const COMMAND_RPC_GET_TRANSACTIONS::entry& e : gettxs_res.txs)
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(e.in_pool, error::wallet_internal_error, "spent tx isn't supposed to be in txpool");
|
||||
@@ -14235,8 +14234,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||
// get received (change) amount
|
||||
std::map<std::string, uint64_t> tx_money_got_in_outs;
|
||||
const auto enote_scan_infos = wallet::view_incoming_scan_transaction(spent_tx,
|
||||
m_account.get_keys(),
|
||||
keystore);
|
||||
m_account);
|
||||
for (const auto &enote_scan_info : enote_scan_infos)
|
||||
if (enote_scan_info && enote_scan_info->subaddr_index)
|
||||
tx_money_got_in_outs[enote_scan_info->asset_type] += enote_scan_info->amount; //! @TODO: check overflow
|
||||
|
||||
+33
-10
@@ -47,7 +47,7 @@
|
||||
#include <random>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
#include "carrot_impl/account.h"
|
||||
#include "carrot_core/account.h"
|
||||
#include "carrot_impl/carrot_offchain_serialization.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_basic/account_boost_serialization.h"
|
||||
@@ -391,6 +391,19 @@ private:
|
||||
return output_public_key;
|
||||
};
|
||||
|
||||
const crypto::public_key get_eph_public_key() const {
|
||||
crypto::public_key eph_public_key;
|
||||
eph_public_key = cryptonote::get_tx_pub_key_from_extra(m_tx);
|
||||
if (eph_public_key != crypto::null_pkey)
|
||||
return eph_public_key;
|
||||
|
||||
const auto additional_pub_keys = cryptonote::get_additional_tx_pub_keys_from_extra(m_tx);
|
||||
if (!additional_pub_keys.empty())
|
||||
return additional_pub_keys[m_internal_output_index];
|
||||
|
||||
return crypto::null_pkey;
|
||||
};
|
||||
|
||||
bool is_carrot() const
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(m_tx.vout.size() <= m_internal_output_index,
|
||||
@@ -1119,11 +1132,8 @@ private:
|
||||
*/
|
||||
bool verify_password(const epee::wipeable_string& password) {crypto::secret_key key = crypto::null_skey; return verify_password(password, key);};
|
||||
bool verify_password(const epee::wipeable_string& password, crypto::secret_key &spend_key_out);
|
||||
cryptonote::account_base& get_account(){return m_account;}
|
||||
const cryptonote::account_base& get_account()const{return m_account;}
|
||||
|
||||
carrot::carrot_and_legacy_account& get_carrot_account(){return m_carrot_account;}
|
||||
const carrot::carrot_and_legacy_account& get_carrot_account()const{return m_carrot_account;}
|
||||
carrot::carrot_and_legacy_account& get_account(){return m_account;}
|
||||
const carrot::carrot_and_legacy_account& get_account()const{return m_account;}
|
||||
|
||||
bool is_key_encryption_enabled() const;
|
||||
void encrypt_keys(const crypto::chacha_key &key);
|
||||
@@ -1182,7 +1192,8 @@ private:
|
||||
boost::optional<cryptonote::subaddress_index> get_subaddress_index(const cryptonote::account_public_address& address) const;
|
||||
crypto::public_key get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const;
|
||||
std::vector<crypto::public_key> get_subaddress_spend_public_keys(uint32_t account, uint32_t begin, uint32_t end) const;
|
||||
std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) const;
|
||||
//std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) const;
|
||||
std::string get_subaddress_as_str(const carrot::subaddress_index_extended& index) const;
|
||||
std::string get_address_as_str() const { return get_subaddress_as_str({0, 0}); }
|
||||
std::string get_integrated_address_as_str(const crypto::hash8& payment_id) const;
|
||||
void add_subaddress_account(const std::string& label);
|
||||
@@ -1275,7 +1286,7 @@ private:
|
||||
bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func);
|
||||
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type tx_type, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose
|
||||
std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, cryptonote::transaction_type tx_type, const std::string& asset_type, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices);
|
||||
std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
|
||||
std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, const cryptonote::transaction_type tx_type, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
|
||||
std::vector<wallet2::pending_tx> create_transactions_return(std::vector<size_t> transfers_indices);
|
||||
std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, const cryptonote::transaction_type tx_type, const std::string& asset_type, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
|
||||
bool sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, const std::vector<cryptonote::tx_destination_entry>& dsts, const unique_index_container& subtract_fee_from_outputs = {}) const;
|
||||
@@ -1405,6 +1416,7 @@ private:
|
||||
if (ver < 20)
|
||||
return;
|
||||
a & m_subaddresses.parent();
|
||||
a & m_subaddresses_extended.parent();
|
||||
std::unordered_map<cryptonote::subaddress_index, crypto::public_key> dummy_subaddresses_inv;
|
||||
a & dummy_subaddresses_inv;
|
||||
a & m_subaddress_labels;
|
||||
@@ -1471,6 +1483,7 @@ private:
|
||||
FIELD(m_scanned_pool_txs[0])
|
||||
FIELD(m_scanned_pool_txs[1])
|
||||
FIELD(m_subaddresses)
|
||||
FIELD(m_subaddresses_extended)
|
||||
FIELD(m_subaddress_labels)
|
||||
FIELD(m_additional_tx_keys)
|
||||
FIELD(m_attributes)
|
||||
@@ -1950,6 +1963,16 @@ private:
|
||||
std::optional<crypto::key_image> &ki_out,
|
||||
bool &password_failure_inout);
|
||||
|
||||
void scan_protocol_tx_output(
|
||||
const cryptonote::transaction& tx,
|
||||
const size_t local_output_index,
|
||||
const crypto::public_key &onetime_address,
|
||||
const uint64_t height,
|
||||
uint64_t &td_origin_idx_out,
|
||||
crypto::public_key locked_coins_pk_out,
|
||||
wallet::enote_view_incoming_scan_info_t &enote_scan_info_out
|
||||
);
|
||||
|
||||
void process_new_transaction(
|
||||
const crypto::hash &txid,
|
||||
const cryptonote::transaction& tx,
|
||||
@@ -2098,8 +2121,7 @@ private:
|
||||
bool should_expand(const cryptonote::subaddress_index &index) const;
|
||||
bool spends_one_of_ours(const cryptonote::transaction &tx) const;
|
||||
|
||||
carrot::carrot_and_legacy_account m_carrot_account;
|
||||
cryptonote::account_base m_account;
|
||||
mutable carrot::carrot_and_legacy_account m_account;
|
||||
boost::optional<epee::net_utils::http::login> m_daemon_login;
|
||||
std::string m_daemon_address;
|
||||
std::string m_proxy;
|
||||
@@ -2124,6 +2146,7 @@ private:
|
||||
serializable_unordered_map<crypto::public_key, size_t> m_pub_keys;
|
||||
cryptonote::account_public_address m_account_public_address;
|
||||
serializable_unordered_map<crypto::public_key, cryptonote::subaddress_index> m_subaddresses;
|
||||
serializable_unordered_map<crypto::public_key, carrot::subaddress_index_extended> m_subaddresses_extended;
|
||||
std::vector<std::vector<std::string>> m_subaddress_labels;
|
||||
serializable_unordered_map<crypto::hash, std::string> m_tx_notes;
|
||||
serializable_unordered_map<std::string, std::string> m_attributes;
|
||||
|
||||
@@ -438,7 +438,9 @@ namespace tools
|
||||
entry.type = pd.m_coinbase ? "block" : "in";
|
||||
entry.subaddr_index = pd.m_subaddr_index;
|
||||
entry.subaddr_indices.push_back(pd.m_subaddr_index);
|
||||
entry.address = m_wallet->get_subaddress_as_str(pd.m_subaddr_index);
|
||||
//entry.address = m_wallet->get_subaddress_as_str(pd.m_subaddr_index);
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
entry.address = m_wallet->get_subaddress_as_str({{pd.m_subaddr_index.major, pd.m_subaddr_index.minor}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward(), pd.m_unlock_time);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -470,7 +472,9 @@ namespace tools
|
||||
entry.subaddr_index = { pd.m_subaddr_account, 0 };
|
||||
for (uint32_t i: pd.m_subaddr_indices)
|
||||
entry.subaddr_indices.push_back({pd.m_subaddr_account, i});
|
||||
entry.address = m_wallet->get_subaddress_as_str({pd.m_subaddr_account, 0});
|
||||
//entry.address = m_wallet->get_subaddress_as_str({pd.m_subaddr_account, 0});
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
entry.address = m_wallet->get_subaddress_as_str({{pd.m_subaddr_account, 0}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward(), pd.m_unlock_time);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -503,7 +507,9 @@ namespace tools
|
||||
entry.subaddr_index = { pd.m_subaddr_account, 0 };
|
||||
for (uint32_t i: pd.m_subaddr_indices)
|
||||
entry.subaddr_indices.push_back({pd.m_subaddr_account, i});
|
||||
entry.address = m_wallet->get_subaddress_as_str({pd.m_subaddr_account, 0});
|
||||
//entry.address = m_wallet->get_subaddress_as_str({pd.m_subaddr_account, 0});
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
entry.address = m_wallet->get_subaddress_as_str({{pd.m_subaddr_account, 0}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward(), pd.m_tx.unlock_time);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -526,7 +532,9 @@ namespace tools
|
||||
entry.type = "pool";
|
||||
entry.subaddr_index = pd.m_subaddr_index;
|
||||
entry.subaddr_indices.push_back(pd.m_subaddr_index);
|
||||
entry.address = m_wallet->get_subaddress_as_str(pd.m_subaddr_index);
|
||||
//entry.address = m_wallet->get_subaddress_as_str(pd.m_subaddr_index);
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
entry.address = m_wallet->get_subaddress_as_str({{pd.m_subaddr_index.major, pd.m_subaddr_index.minor}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
set_confirmations(entry, m_wallet->get_blockchain_current_height(), m_wallet->get_last_block_reward(), pd.m_unlock_time);
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
@@ -534,6 +542,8 @@ namespace tools
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
|
||||
std::vector<std::string> assets_in_wallet = m_wallet->list_asset_types();
|
||||
std::string asset_type = req.asset_type.empty() ? "SAL1" : boost::algorithm::to_upper_copy(req.asset_type);
|
||||
// verify that the asset is in the list of in-wallet assets
|
||||
@@ -590,7 +600,7 @@ namespace tools
|
||||
info.account_index = account_index;
|
||||
info.address_index = i;
|
||||
cryptonote::subaddress_index index = {info.account_index, info.address_index};
|
||||
info.address = m_wallet->get_subaddress_as_str(index);
|
||||
info.address = m_wallet->get_subaddress_as_str({{info.account_index, info.address_index}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
info.balance = balance_per_subaddress[i];
|
||||
info.unlocked_balance = unlocked_balance_per_subaddress[i].first;
|
||||
info.blocks_to_unlock = unlocked_balance_per_subaddress[i].second.first;
|
||||
@@ -616,6 +626,9 @@ namespace tools
|
||||
bool wallet_rpc_server::on_getaddress(const wallet_rpc::COMMAND_RPC_GET_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
|
||||
try
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(req.account_index >= m_wallet->get_num_subaddress_accounts(), error::account_index_outofbound);
|
||||
@@ -638,7 +651,8 @@ namespace tools
|
||||
res.addresses.resize(res.addresses.size() + 1);
|
||||
auto& info = res.addresses.back();
|
||||
const cryptonote::subaddress_index index = {req.account_index, i};
|
||||
info.address = m_wallet->get_subaddress_as_str(index);
|
||||
//info.address = m_wallet->get_subaddress_as_str(index);
|
||||
info.address = m_wallet->get_subaddress_as_str({{req.account_index, i}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
info.label = m_wallet->get_subaddress_label(index);
|
||||
info.address_index = index.minor;
|
||||
info.used = std::find_if(transfers.begin(), transfers.end(), [&](const tools::wallet2::transfer_details& td) { return td.m_subaddr_index == index; }) != transfers.end();
|
||||
@@ -731,6 +745,9 @@ namespace tools
|
||||
bool wallet_rpc_server::on_get_accounts(const wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
|
||||
try
|
||||
{
|
||||
res.total_balance = 0;
|
||||
@@ -751,7 +768,8 @@ namespace tools
|
||||
continue;
|
||||
wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::subaddress_account_info info;
|
||||
info.account_index = subaddr_index.major;
|
||||
info.base_address = m_wallet->get_subaddress_as_str(subaddr_index);
|
||||
//info.base_address = m_wallet->get_subaddress_as_str(subaddr_index);
|
||||
info.base_address = m_wallet->get_subaddress_as_str({{subaddr_index.major, subaddr_index.minor}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
|
||||
//for (const auto& asset: asset_types) {
|
||||
info.balance = m_wallet->balance(subaddr_index.major, "SAL1", req.strict_balances);
|
||||
@@ -1873,7 +1891,7 @@ namespace tools
|
||||
{
|
||||
uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0);
|
||||
uint32_t priority = m_wallet->adjust_priority(req.priority);
|
||||
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra);
|
||||
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, cryptonote::transaction_type::TRANSFER, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra);
|
||||
|
||||
if (ptx_vector.empty())
|
||||
{
|
||||
@@ -2084,6 +2102,9 @@ namespace tools
|
||||
bool wallet_rpc_server::on_get_payments(const wallet_rpc::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
if (!m_wallet) return not_open(er);
|
||||
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
|
||||
crypto::hash payment_id;
|
||||
crypto::hash8 payment_id8;
|
||||
cryptonote::blobdata payment_id_blob;
|
||||
@@ -2124,7 +2145,8 @@ namespace tools
|
||||
rpc_payment.unlock_time = payment.m_unlock_time;
|
||||
rpc_payment.locked = !m_wallet->is_transfer_unlocked(payment.m_unlock_time, payment.m_block_height);
|
||||
rpc_payment.subaddr_index = payment.m_subaddr_index;
|
||||
rpc_payment.address = m_wallet->get_subaddress_as_str(payment.m_subaddr_index);
|
||||
//rpc_payment.address = m_wallet->get_subaddress_as_str(payment.m_subaddr_index);
|
||||
rpc_payment.address = m_wallet->get_subaddress_as_str({{payment.m_subaddr_index.major, payment.m_subaddr_index.minor}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
res.payments.push_back(rpc_payment);
|
||||
}
|
||||
|
||||
@@ -2134,6 +2156,9 @@ namespace tools
|
||||
bool wallet_rpc_server::on_get_bulk_payments(const wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::request& req, wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS::response& res, epee::json_rpc::error& er, const connection_context *ctx)
|
||||
{
|
||||
res.payments.clear();
|
||||
|
||||
bool is_carrot = m_wallet->get_current_hard_fork() >= HF_VERSION_CARROT;
|
||||
|
||||
if (!m_wallet) return not_open(er);
|
||||
|
||||
/* If the payment ID list is empty, we get payments to any payment ID (or lack thereof) */
|
||||
@@ -2151,7 +2176,8 @@ namespace tools
|
||||
rpc_payment.block_height = payment.second.m_block_height;
|
||||
rpc_payment.unlock_time = payment.second.m_unlock_time;
|
||||
rpc_payment.subaddr_index = payment.second.m_subaddr_index;
|
||||
rpc_payment.address = m_wallet->get_subaddress_as_str(payment.second.m_subaddr_index);
|
||||
//rpc_payment.address = m_wallet->get_subaddress_as_str(payment.second.m_subaddr_index);
|
||||
rpc_payment.address = m_wallet->get_subaddress_as_str({{payment.second.m_subaddr_index.major, payment.second.m_subaddr_index.minor}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
rpc_payment.locked = !m_wallet->is_transfer_unlocked(payment.second.m_unlock_time, payment.second.m_block_height);
|
||||
res.payments.push_back(std::move(rpc_payment));
|
||||
}
|
||||
@@ -2206,7 +2232,8 @@ namespace tools
|
||||
rpc_payment.block_height = payment.m_block_height;
|
||||
rpc_payment.unlock_time = payment.m_unlock_time;
|
||||
rpc_payment.subaddr_index = payment.m_subaddr_index;
|
||||
rpc_payment.address = m_wallet->get_subaddress_as_str(payment.m_subaddr_index);
|
||||
//rpc_payment.address = m_wallet->get_subaddress_as_str(payment.m_subaddr_index);
|
||||
rpc_payment.address = m_wallet->get_subaddress_as_str({{payment.m_subaddr_index.major, payment.m_subaddr_index.minor}, is_carrot ? carrot::AddressDeriveType::Carrot : carrot::AddressDeriveType::PreCarrot});
|
||||
rpc_payment.locked = !m_wallet->is_transfer_unlocked(payment.m_unlock_time, payment.m_block_height);
|
||||
res.payments.push_back(std::move(rpc_payment));
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ using namespace cryptonote;
|
||||
void wallet_accessor_test::set_account(tools::wallet2 * wallet, cryptonote::account_base& account)
|
||||
{
|
||||
wallet->clear();
|
||||
wallet->m_account = account;
|
||||
// wallet->m_account = reinterpret_cast<carrot::carrot_and_legacy_account&>(account);
|
||||
|
||||
wallet->m_key_device_type = account.get_device().get_type();
|
||||
wallet->m_account_public_address = account.get_keys().m_account_address;
|
||||
|
||||
@@ -222,6 +222,7 @@ public:
|
||||
carrot::RCTOutputEnoteProposal output_proposal;
|
||||
carrot::get_output_proposal_normal_v1(payment_proposal,
|
||||
{},
|
||||
nullptr,
|
||||
output_proposal,
|
||||
m_encrypted_payment_id);
|
||||
m_enote = output_proposal.enote;
|
||||
|
||||
@@ -115,6 +115,7 @@ TEST(carrot_core, main_address_normal_scan_completeness)
|
||||
encrypted_payment_id_t encrypted_payment_id;
|
||||
get_output_proposal_normal_v1(proposal,
|
||||
tx_first_key_image,
|
||||
nullptr, // s_view_balance_dev
|
||||
enote_proposal,
|
||||
encrypted_payment_id);
|
||||
|
||||
@@ -185,6 +186,7 @@ TEST(carrot_core, subaddress_normal_scan_completeness)
|
||||
encrypted_payment_id_t encrypted_payment_id;
|
||||
get_output_proposal_normal_v1(proposal,
|
||||
tx_first_key_image,
|
||||
nullptr, // s_view_balance_dev
|
||||
enote_proposal,
|
||||
encrypted_payment_id);
|
||||
|
||||
@@ -252,6 +254,7 @@ TEST(carrot_core, integrated_address_normal_scan_completeness)
|
||||
encrypted_payment_id_t encrypted_payment_id;
|
||||
get_output_proposal_normal_v1(proposal,
|
||||
tx_first_key_image,
|
||||
nullptr, // s_view_balance_dev
|
||||
enote_proposal,
|
||||
encrypted_payment_id);
|
||||
|
||||
@@ -320,10 +323,13 @@ TEST(carrot_core, main_address_special_scan_completeness)
|
||||
const crypto::key_image tx_first_key_image = rct::rct2ki(rct::pkGen());
|
||||
|
||||
RCTOutputEnoteProposal enote_proposal;
|
||||
RCTOutputEnoteProposal return_enote;
|
||||
get_output_proposal_special_v1(proposal,
|
||||
keys.k_view_incoming_dev,
|
||||
tx_first_key_image,
|
||||
cryptonote::transaction_type::TRANSFER, // tx_type
|
||||
std::nullopt,
|
||||
return_enote,
|
||||
enote_proposal);
|
||||
|
||||
ASSERT_EQ(proposal.amount, enote_proposal.amount);
|
||||
@@ -397,10 +403,13 @@ TEST(carrot_core, subaddress_special_scan_completeness)
|
||||
const crypto::key_image tx_first_key_image = rct::rct2ki(rct::pkGen());
|
||||
|
||||
RCTOutputEnoteProposal enote_proposal;
|
||||
RCTOutputEnoteProposal return_enote;
|
||||
get_output_proposal_special_v1(proposal,
|
||||
keys.k_view_incoming_dev,
|
||||
tx_first_key_image,
|
||||
cryptonote::transaction_type::TRANSFER, // tx_type
|
||||
std::nullopt,
|
||||
return_enote,
|
||||
enote_proposal);
|
||||
|
||||
ASSERT_EQ(proposal.amount, enote_proposal.amount);
|
||||
@@ -711,6 +720,8 @@ static void subtest_2out_transfer_get_output_enote_proposals_completeness(const
|
||||
std::vector<RCTOutputEnoteProposal> enote_proposals;
|
||||
encrypted_payment_id_t encrypted_payment_id;
|
||||
size_t change_index;
|
||||
RCTOutputEnoteProposal return_enote;
|
||||
std::unordered_map<crypto::public_key, size_t> normal_payments_indices;
|
||||
get_output_enote_proposals({bob_payment_proposal},
|
||||
{alice_payment_proposal},
|
||||
dummy_encrypted_pid,
|
||||
@@ -718,8 +729,11 @@ static void subtest_2out_transfer_get_output_enote_proposals_completeness(const
|
||||
&alice.k_view_incoming_dev,
|
||||
tx_first_key_image,
|
||||
enote_proposals,
|
||||
return_enote,
|
||||
encrypted_payment_id,
|
||||
change_index);
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
change_index,
|
||||
normal_payments_indices);
|
||||
|
||||
ASSERT_EQ(2, enote_proposals.size()); // 2-out tx
|
||||
|
||||
|
||||
@@ -339,6 +339,7 @@ TEST(carrot_fcmp, receive_scan_spend_and_verify_serialized_carrot_tx)
|
||||
/*selfsend_payment_proposals=*/{},
|
||||
fee_per_weight,
|
||||
/*extra=*/{},
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
[&input_info_by_ki]
|
||||
(
|
||||
const boost::multiprecision::int128_t&,
|
||||
@@ -375,6 +376,7 @@ TEST(carrot_fcmp, receive_scan_spend_and_verify_serialized_carrot_tx)
|
||||
std::vector<RCTOutputEnoteProposal> output_enote_proposals;
|
||||
encrypted_payment_id_t encrypted_payment_id;
|
||||
size_t change_index;
|
||||
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,
|
||||
@@ -384,7 +386,9 @@ TEST(carrot_fcmp, receive_scan_spend_and_verify_serialized_carrot_tx)
|
||||
tx_proposal.key_images_sorted.at(0),
|
||||
output_enote_proposals,
|
||||
encrypted_payment_id,
|
||||
change_index);
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
change_index,
|
||||
normal_payments_indices);
|
||||
|
||||
// Collect balance info and enotes
|
||||
std::vector<crypto::public_key> input_onetime_addresses;
|
||||
@@ -413,6 +417,10 @@ TEST(carrot_fcmp, receive_scan_spend_and_verify_serialized_carrot_tx)
|
||||
tx_proposal.key_images_sorted,
|
||||
tx_proposal.sources,
|
||||
tx_proposal.fee,
|
||||
tx_proposal.tx_type,
|
||||
tx_proposal.amount_burnt,
|
||||
{}, // change_masks
|
||||
{}, // return_enote
|
||||
encrypted_payment_id);
|
||||
|
||||
ASSERT_EQ(2, tx.version);
|
||||
|
||||
@@ -158,7 +158,9 @@ static void subtest_multi_account_transfer_over_transaction(const unittest_trans
|
||||
make_carrot_transaction_proposal_v1_transfer(normal_payment_proposals,
|
||||
selfsend_payment_proposals,
|
||||
tx_preproposal.fee_per_weight,
|
||||
5,
|
||||
tx_preproposal.extra_extra,
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
make_fake_input_selection_callback(),
|
||||
ss_keys.carrot_account_spend_pubkey,
|
||||
{{0, 0}, AddressDeriveType::Carrot},
|
||||
@@ -204,6 +206,8 @@ static void subtest_multi_account_transfer_over_transaction(const unittest_trans
|
||||
std::vector<RCTOutputEnoteProposal> rederived_output_enote_proposals;
|
||||
encrypted_payment_id_t rederived_encrypted_payment_id;
|
||||
size_t change_index;
|
||||
RCTOutputEnoteProposal return_enote;
|
||||
std::unordered_map<crypto::public_key, size_t> normal_payments_indices;
|
||||
get_output_enote_proposals(tx_proposal.normal_payment_proposals,
|
||||
modified_selfsend_payment_proposals,
|
||||
*parsed_encrypted_payment_id,
|
||||
@@ -211,8 +215,11 @@ static void subtest_multi_account_transfer_over_transaction(const unittest_trans
|
||||
&ss_keys.k_view_incoming_dev,
|
||||
parsed_key_images.at(0),
|
||||
rederived_output_enote_proposals,
|
||||
return_enote,
|
||||
rederived_encrypted_payment_id,
|
||||
change_index);
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
change_index,
|
||||
normal_payments_indices);
|
||||
EXPECT_EQ(*parsed_encrypted_payment_id, rederived_encrypted_payment_id);
|
||||
ASSERT_EQ(parsed_enotes.size(), rederived_output_enote_proposals.size());
|
||||
for (size_t enote_idx = 0; enote_idx < parsed_enotes.size(); ++enote_idx)
|
||||
|
||||
@@ -188,6 +188,8 @@ static void subtest_legacy_2out_transfer_get_output_enote_proposals_completeness
|
||||
std::vector<RCTOutputEnoteProposal> enote_proposals;
|
||||
encrypted_payment_id_t encrypted_payment_id;
|
||||
size_t change_index;
|
||||
RCTOutputEnoteProposal return_enote;
|
||||
std::unordered_map<crypto::public_key, size_t> normal_payments_indices;
|
||||
get_output_enote_proposals({bob_payment_proposal},
|
||||
{alice_payment_proposal},
|
||||
gen_encrypted_payment_id(),
|
||||
@@ -195,8 +197,11 @@ static void subtest_legacy_2out_transfer_get_output_enote_proposals_completeness
|
||||
&alive_k_v_dev,
|
||||
tx_first_key_image,
|
||||
enote_proposals,
|
||||
return_enote,
|
||||
encrypted_payment_id,
|
||||
change_index);
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
change_index,
|
||||
normal_payments_indices);
|
||||
|
||||
ASSERT_EQ(2, enote_proposals.size()); // 2-out tx
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ std::tuple<std::vector<RCTOutputEnoteProposal>, crypto::public_key> make_origin_
|
||||
.randomness = randomness
|
||||
},
|
||||
tx_first_key_image,
|
||||
nullptr, // s_view_balance_dev
|
||||
enote_proposal_out,
|
||||
encrypted_payment_id_out
|
||||
);
|
||||
@@ -225,6 +226,7 @@ std::tuple<std::vector<RCTOutputEnoteProposal>, crypto::public_key> make_return_
|
||||
get_output_proposal_return_v1(
|
||||
proposal_return,
|
||||
tx_return_first_key_image,
|
||||
nullptr, // s_view_balance_dev
|
||||
enote_proposal_return,
|
||||
encrypted_payment_id_return
|
||||
);
|
||||
|
||||
@@ -56,9 +56,8 @@ namespace test
|
||||
source_amount += input.value().amount;
|
||||
auto const& key = boost::get<cryptonote::txout_to_tagged_key>(input.value().target);
|
||||
|
||||
actual_sources.push_back(
|
||||
{{}, 0, key_field.pub_key, {}, std::size_t(input.index()), input.value().amount, rct, rct::identity()}
|
||||
);
|
||||
cryptonote::tx_source_entry foo{{}, 0, key_field.pub_key, {}, std::size_t(input.index()), input.value().amount, rct, false, false, rct::identity(), {}, "SAL1"};
|
||||
actual_sources.push_back(foo);
|
||||
|
||||
for (unsigned ring = 0; ring < 10; ++ring)
|
||||
actual_sources.back().push_output(input.index(), key.key, input.value().amount);
|
||||
|
||||
@@ -407,7 +407,9 @@ cryptonote::transaction construct_carrot_pruned_transaction_fake_inputs(
|
||||
normal_payment_proposals,
|
||||
selfsend_payment_proposals,
|
||||
fake_fee_per_weight,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
std::move(select_inputs),
|
||||
acc_keys.m_account_address.m_spend_public_key,
|
||||
{{0, 0}, carrot::AddressDeriveType::PreCarrot},
|
||||
|
||||
@@ -42,13 +42,13 @@
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
TEST(wallet_scanning, view_scan_as_sender_mainaddr)
|
||||
{
|
||||
cryptonote::account_base aether;
|
||||
aether.generate();
|
||||
carrot::carrot_and_legacy_account aether;
|
||||
aether.generate();
|
||||
|
||||
cryptonote::account_base bob;
|
||||
bob.generate();
|
||||
const cryptonote::account_public_address bob_main_addr = bob.get_keys().m_account_address;
|
||||
const crypto::public_key bob_main_spend_pubkey = bob_main_addr.m_spend_public_key;
|
||||
carrot::carrot_and_legacy_account bob;
|
||||
bob.generate();
|
||||
const cryptonote::account_public_address bob_main_addr = bob.get_keys().m_account_address;
|
||||
const crypto::public_key bob_main_spend_pubkey = bob_main_addr.m_spend_public_key;
|
||||
|
||||
const rct::xmr_amount amount = rct::randXmrAmount(10 * COIN);
|
||||
|
||||
@@ -88,9 +88,10 @@ TEST(wallet_scanning, view_scan_as_sender_mainaddr)
|
||||
// call view_incoming_scan_transaction with no meaningful key nor subaddresses maps,
|
||||
// just with the proper ECDH
|
||||
const auto enote_scan_infos = tools::wallet::view_incoming_scan_transaction_as_sender(tx,
|
||||
{&main_derivation, 1},
|
||||
{},
|
||||
bob_main_addr);
|
||||
{&main_derivation, 1},
|
||||
{},
|
||||
bob_main_addr
|
||||
);
|
||||
|
||||
bool matched = false;
|
||||
for (const auto &enote_scan_info : enote_scan_infos)
|
||||
@@ -109,11 +110,11 @@ TEST(wallet_scanning, view_scan_as_sender_mainaddr)
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
TEST(wallet_scanning, view_scan_long_payment_id)
|
||||
{
|
||||
cryptonote::account_base aether;
|
||||
aether.generate();
|
||||
carrot::carrot_and_legacy_account aether;
|
||||
aether.generate();
|
||||
|
||||
cryptonote::account_base bob;
|
||||
bob.generate();
|
||||
carrot::carrot_and_legacy_account bob;
|
||||
bob.generate();
|
||||
const cryptonote::account_public_address bob_main_addr = bob.get_keys().m_account_address;
|
||||
const crypto::public_key bob_main_spend_pubkey = bob_main_addr.m_spend_public_key;
|
||||
|
||||
@@ -160,9 +161,8 @@ TEST(wallet_scanning, view_scan_long_payment_id)
|
||||
// just with the proper ECDH
|
||||
std::vector<std::optional<tools::wallet::enote_view_incoming_scan_info_t>> enote_scan_infos(tx.vout.size());
|
||||
tools::wallet::view_incoming_scan_transaction(tx,
|
||||
bob.get_keys(),
|
||||
{{bob_main_spend_pubkey, {}}}, // use a fake subaddress map with just the provided address in it
|
||||
epee::to_mut_span(enote_scan_infos));
|
||||
bob,
|
||||
epee::to_mut_span(enote_scan_infos));
|
||||
|
||||
bool matched = false;
|
||||
for (const auto &enote_scan_info : enote_scan_infos)
|
||||
@@ -182,11 +182,11 @@ TEST(wallet_scanning, view_scan_long_payment_id)
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
TEST(wallet_scanning, view_scan_short_payment_id)
|
||||
{
|
||||
cryptonote::account_base aether;
|
||||
aether.generate();
|
||||
carrot::carrot_and_legacy_account aether;
|
||||
aether.generate();
|
||||
|
||||
cryptonote::account_base bob;
|
||||
bob.generate();
|
||||
carrot::carrot_and_legacy_account bob;
|
||||
bob.generate();
|
||||
const cryptonote::account_public_address bob_main_addr = bob.get_keys().m_account_address;
|
||||
const crypto::public_key bob_main_spend_pubkey = bob_main_addr.m_spend_public_key;
|
||||
|
||||
@@ -237,9 +237,8 @@ TEST(wallet_scanning, view_scan_short_payment_id)
|
||||
// just with the proper ECDH
|
||||
std::vector<std::optional<tools::wallet::enote_view_incoming_scan_info_t>> enote_scan_infos(tx.vout.size());
|
||||
tools::wallet::view_incoming_scan_transaction(tx,
|
||||
bob.get_keys(),
|
||||
{{bob_main_spend_pubkey, {}}}, // use a fake subaddress map with just the provided address in it
|
||||
epee::to_mut_span(enote_scan_infos));
|
||||
bob,
|
||||
epee::to_mut_span(enote_scan_infos));
|
||||
|
||||
bool matched = false;
|
||||
for (const auto &enote_scan_info : enote_scan_infos)
|
||||
|
||||
@@ -160,16 +160,16 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_transfer_1)
|
||||
const uint64_t top_block_index = std::max(transfers.front().m_block_height, transfers.back().m_block_height)
|
||||
+ CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
|
||||
|
||||
tools::wallet2 w;
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_transfer(
|
||||
transfers,
|
||||
{{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
w,
|
||||
dsts,
|
||||
/*fee_per_weight=*/1,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
/*tx_type=*/cryptonote::transaction_type::TRANSFER,
|
||||
/*subaddr_account=*/0,
|
||||
/*subaddr_indices=*/{},
|
||||
/*ignore_above=*/MONEY_SUPPLY,
|
||||
/*ignore_below=*/0,
|
||||
{},
|
||||
top_block_index);
|
||||
|
||||
@@ -223,16 +223,16 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_transfer_2)
|
||||
carrot::mock::convert_destination_v1(bob.cryptonote_address(), out_amount)
|
||||
};
|
||||
|
||||
tools::wallet2 w;
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_transfer(
|
||||
transfers,
|
||||
alice.subaddress_map_cn(),
|
||||
w,
|
||||
dsts,
|
||||
/*fee_per_weight=*/1,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
/*tx_type=*/cryptonote::transaction_type::TRANSFER,
|
||||
/*subaddr_account=*/spending_subaddr_account,
|
||||
/*subaddr_indices=*/{},
|
||||
/*ignore_above=*/MONEY_SUPPLY,
|
||||
/*ignore_below=*/0,
|
||||
{},
|
||||
top_block_index);
|
||||
|
||||
@@ -290,15 +290,19 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_sweep_1)
|
||||
|
||||
const tools::wallet2::transfer_container transfers{gen_transfer_details()};
|
||||
|
||||
tools::wallet2 w;
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(
|
||||
transfers,
|
||||
{{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
// transfers,
|
||||
// {{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
w,
|
||||
{transfers.front().m_key_image},
|
||||
bob.get_keys().m_account_address,
|
||||
/*is_subaddress=*/false,
|
||||
/*n_dests_per_tx=*/1,
|
||||
/*fee_per_weight=*/1,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
/*tx_type=*/cryptonote::transaction_type::TRANSFER,
|
||||
transfers.front().m_block_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE);
|
||||
ASSERT_EQ(1, tx_proposals.size());
|
||||
const carrot::CarrotTransactionProposalV1 &tx_proposal = tx_proposals.at(0);
|
||||
@@ -323,16 +327,19 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_sweep_2)
|
||||
bob.generate();
|
||||
|
||||
const tools::wallet2::transfer_container transfers{gen_transfer_details()};
|
||||
|
||||
tools::wallet2 w;
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(
|
||||
transfers,
|
||||
{{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
// transfers,
|
||||
// {{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
w,
|
||||
{transfers.front().m_key_image},
|
||||
bob.get_keys().m_account_address,
|
||||
/*is_subaddress=*/false,
|
||||
/*n_dests_per_tx=*/FCMP_PLUS_PLUS_MAX_OUTPUTS - 1,
|
||||
/*fee_per_weight=*/1,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
/*tx_type=*/cryptonote::transaction_type::TRANSFER,
|
||||
transfers.front().m_block_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE);
|
||||
ASSERT_EQ(1, tx_proposals.size());
|
||||
const carrot::CarrotTransactionProposalV1 &tx_proposal = tx_proposals.at(0);
|
||||
@@ -365,16 +372,19 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_sweep_3)
|
||||
alice.generate();
|
||||
|
||||
const tools::wallet2::transfer_container transfers{gen_transfer_details()};
|
||||
|
||||
tools::wallet2 w;
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(
|
||||
transfers,
|
||||
{{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
// transfers,
|
||||
// {{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
w,
|
||||
{transfers.front().m_key_image},
|
||||
alice.get_keys().m_account_address,
|
||||
/*is_subaddress=*/false,
|
||||
/*n_dests_per_tx=*/FCMP_PLUS_PLUS_MAX_OUTPUTS,
|
||||
/*fee_per_weight=*/1,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
/*tx_type=*/cryptonote::transaction_type::TRANSFER,
|
||||
transfers.front().m_block_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE);
|
||||
ASSERT_EQ(1, tx_proposals.size());
|
||||
const carrot::CarrotTransactionProposalV1 &tx_proposal = tx_proposals.at(0);
|
||||
@@ -441,15 +451,19 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_sweep_4)
|
||||
const size_t n_dests_per_tx = 4;
|
||||
|
||||
// make tx proposals
|
||||
tools::wallet2 w;
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(
|
||||
transfers,
|
||||
{{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
// transfers,
|
||||
// {{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
w,
|
||||
selected_key_images,
|
||||
bob.get_keys().m_account_address,
|
||||
/*is_subaddress=*/false,
|
||||
/*n_dests_per_tx=*/n_dests_per_tx,
|
||||
/*fee_per_weight=*/1,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
/*tx_type=*/cryptonote::transaction_type::TRANSFER,
|
||||
top_block_index);
|
||||
ASSERT_EQ(4, tx_proposals.size());
|
||||
|
||||
@@ -522,15 +536,19 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_sweep_5)
|
||||
const size_t n_dests_per_tx = 8;
|
||||
|
||||
// make tx proposals
|
||||
tools::wallet2 w;
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(
|
||||
transfers,
|
||||
{{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
// transfers,
|
||||
// {{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
w,
|
||||
selected_key_images,
|
||||
alice.get_keys().m_account_address,
|
||||
/*is_subaddress=*/false,
|
||||
/*n_dests_per_tx=*/n_dests_per_tx,
|
||||
/*fee_per_weight=*/1,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
/*tx_type=*/cryptonote::transaction_type::TRANSFER,
|
||||
top_block_index);
|
||||
ASSERT_EQ(8, tx_proposals.size());
|
||||
|
||||
@@ -606,15 +624,19 @@ TEST(wallet_tx_builder, make_carrot_transaction_proposals_wallet2_sweep_6)
|
||||
const size_t n_dests_per_tx = 2;
|
||||
|
||||
// make tx proposals
|
||||
tools::wallet2 w;
|
||||
const std::vector<carrot::CarrotTransactionProposalV1> tx_proposals = tools::wallet::make_carrot_transaction_proposals_wallet2_sweep(
|
||||
transfers,
|
||||
{{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
// transfers,
|
||||
// {{alice.get_keys().m_account_address.m_spend_public_key, {}}},
|
||||
w,
|
||||
selected_key_images,
|
||||
alice.get_keys().m_account_address,
|
||||
/*is_subaddress=*/false,
|
||||
/*n_dests_per_tx=*/n_dests_per_tx,
|
||||
/*fee_per_weight=*/1,
|
||||
5,
|
||||
/*extra=*/{},
|
||||
/*tx_type=*/cryptonote::transaction_type::TRANSFER,
|
||||
top_block_index);
|
||||
ASSERT_EQ(1, tx_proposals.size());
|
||||
const carrot::CarrotTransactionProposalV1 &tx_proposal = tx_proposals.at(0);
|
||||
|
||||
Reference in New Issue
Block a user