Compare commits
50 Commits
v0.9.9-rc4
...
v1.0.0-rc2
| Author | SHA1 | Date | |
|---|---|---|---|
| 91814ebfd9 | |||
| 7b3e8007c8 | |||
| 141761957d | |||
| b2ab2f606c | |||
| 40f0420e02 | |||
| 44e54ad555 | |||
| 69407ed8a5 | |||
| 13ee838f3c | |||
| ec33664734 | |||
| bfe8c4606d | |||
| a159bed3ba | |||
| 52f2065db4 | |||
| 0fd570a2c4 | |||
| 7df7f2740d | |||
| 458af34c67 | |||
| 21a3f5ca6f | |||
| bc7a797b71 | |||
| 9e888834e7 | |||
| 9709fad4d6 | |||
| 906e55f87b | |||
| 92812621be | |||
| 82b14a776f | |||
| 54a33225a2 | |||
| d7584de579 | |||
| a4c0d85bbb | |||
| 609615779c | |||
| b9364b5749 | |||
| 7cd7bef3ca | |||
| 80bd2d1ff0 | |||
| cbe84499fb | |||
| a8ee0a90e0 | |||
| c9de861216 | |||
| 0239202f09 | |||
| 2dd6208a80 | |||
| 37594fe8fa | |||
| e5c9b05ed6 | |||
| 9ba621b3ae | |||
| 9e20133ed9 | |||
| 9c11200666 | |||
| 3e0649a8d2 | |||
| b87bfe002a | |||
| f2e69594a7 | |||
| 7b39504050 | |||
| eff99e9287 | |||
| 6f8fcdab03 | |||
| c7a739d885 | |||
| 608962068a | |||
| e7615b4c08 | |||
| 28a9338ab7 | |||
| 1d3747e9cd |
@@ -1,4 +1,4 @@
|
||||
# Salvium Zero v0.9.9
|
||||
# Salvium One v1.0.0
|
||||
|
||||
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.9
|
||||
git checkout v1.0.0
|
||||
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.9
|
||||
git checkout v1.0.0
|
||||
```
|
||||
|
||||
* 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.9'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v1.0.0'. If you don't care about the version and just want binaries from master, skip this step:
|
||||
|
||||
```bash
|
||||
git checkout v0.9.9
|
||||
git checkout v1.0.0
|
||||
```
|
||||
|
||||
* If you are on a 64-bit system, run:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
OSX_MIN_VERSION=10.13
|
||||
OSX_MIN_VERSION=11.0
|
||||
LD64_VERSION=609
|
||||
ifeq (aarch64, $(host_arch))
|
||||
CC_target=arm64-apple-$(host_os)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
mingw32_CFLAGS=-pipe -pthread
|
||||
mingw32_CFLAGS=-pipe
|
||||
mingw32_CXXFLAGS=$(mingw32_CFLAGS)
|
||||
mingw32_ARFLAGS=cr
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
package=boost
|
||||
$(package)_version=1.66.0
|
||||
package=boost
|
||||
$(package)_version=1.84.0
|
||||
$(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/
|
||||
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz
|
||||
$(package)_sha256_hash=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60
|
||||
$(package)_dependencies=libiconv
|
||||
$(package)_patches=fix_aroptions.patch fix_arm_arch.patch
|
||||
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.bz2
|
||||
$(package)_sha256_hash=cc4b893acf645c9d4b698e9a0f08ca8846aa5d6c68275c14c3e7949c24109454
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts_release=variant=release
|
||||
$(package)_config_opts_debug=variant=debug
|
||||
$(package)_config_opts=--layout=tagged --build-type=complete --user-config=user-config.jam
|
||||
$(package)_config_opts+=--layout=system --user-config=user-config.jam variant=release
|
||||
$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1
|
||||
$(package)_config_opts_linux=threadapi=pthread runtime-link=shared
|
||||
$(package)_config_opts_android=threadapi=pthread runtime-link=static target-os=android
|
||||
$(package)_config_opts_darwin=--toolset=darwin runtime-link=shared
|
||||
$(package)_config_opts_darwin=--toolset=darwin runtime-link=shared target-os=darwin
|
||||
$(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static
|
||||
$(package)_config_opts_x86_64_mingw32=address-model=64
|
||||
$(package)_config_opts_i686_mingw32=address-model=32
|
||||
@@ -22,20 +20,20 @@ $(package)_toolset_$(host_os)=gcc
|
||||
$(package)_archiver_$(host_os)=$($(package)_ar)
|
||||
$(package)_toolset_darwin=darwin
|
||||
$(package)_archiver_darwin=$($(package)_libtool)
|
||||
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
|
||||
$(package)_cxxflags=-std=c++11
|
||||
$(package)_cxxflags_linux=-fPIC
|
||||
$(package)_cxxflags_freebsd=-fPIC -DBOOST_ASIO_HAS_STD_STRING_VIEW=1
|
||||
$(package)_config_libraries_$(host_os)="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization"
|
||||
$(package)_config_libraries_mingw32="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale"
|
||||
$(package)_cxxflags=-std=c++17
|
||||
$(package)_cxxflags_linux+=-fPIC
|
||||
$(package)_cxxflags_freebsd+=-fPIC
|
||||
$(package)_cxxflags_darwin+=-ffile-prefix-map=$($(package)_extract_dir)=/usr
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/fix_aroptions.patch &&\
|
||||
patch -p1 < $($(package)_patch_dir)/fix_arm_arch.patch &&\
|
||||
echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : <cxxflags>\"$($(package)_cxxflags) $($(package)_cppflags)\" <linkflags>\"$($(package)_ldflags)\" <archiver>\"$(boost_archiver_$(host_os))\" <arflags>\"$($(package)_arflags)\" <striper>\"$(host_STRIP)\" <ranlib>\"$(host_RANLIB)\" <rc>\"$(host_WINDRES)\" : ;" > user-config.jam
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries)
|
||||
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries_$(host_os))
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
|
||||
@@ -5,17 +5,18 @@ $(package)_download_file=$($(package)_version).tar.gz
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=70a7189418c2086d20c299c5d59250cf5940782c778892ccc899c66516ed240e
|
||||
$(package)_build_subdir=cctools
|
||||
$(package)_dependencies=native_clang native_libtapi
|
||||
$(package)_patches=no-build-date.patch
|
||||
$(package)_dependencies=native_libtapi
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--target=$(host) --disable-lto-support --with-libtapi=$(host_prefix)
|
||||
$(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib
|
||||
$(package)_cc=$(host_prefix)/native/bin/clang
|
||||
$(package)_cxx=$(host_prefix)/native/bin/clang++
|
||||
$(package)_cc=$(clang_prog)
|
||||
$(package)_cxx=$(clangxx_prog)
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub cctools && \
|
||||
patch -p1 < $($(package)_patch_dir)/no-build-date.patch
|
||||
endef
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
package=native_clang
|
||||
$(package)_version=9.0.0
|
||||
$(package)_download_path=https://releases.llvm.org/$($(package)_version)
|
||||
$(package)_download_file=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
$(package)_file_name=clang-llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
$(package)_sha256_hash=a23b082b30c128c9831dbdd96edad26b43f56624d0ad0ea9edec506f5385038d
|
||||
#$(package)_version=9.0.0
|
||||
#$(package)_download_path=https://releases.llvm.org/$($(package)_version)
|
||||
#$(package)_download_file=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
#$(package)_file_name=clang-llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-18.04.tar.xz
|
||||
#$(package)_sha256_hash=a23b082b30c128c9831dbdd96edad26b43f56624d0ad0ea9edec506f5385038d
|
||||
|
||||
$(package)_version=12.0.0
|
||||
$(package)_download_path=https://github.com/llvm/llvm-project/releases/download/llvmorg-$($(package)_version)
|
||||
$(package)_download_file=clang+llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-20.04.tar.xz
|
||||
$(package)_file_name=clang-llvm-$($(package)_version)-x86_64-linux-gnu-ubuntu-20.04.tar.xz
|
||||
$(package)_sha256_hash=a9ff205eb0b73ca7c86afc6432eed1c2d49133bd0d49e47b15be59bbf0dd292e
|
||||
|
||||
define $(package)_extract_cmds
|
||||
echo $($(package)_sha256_hash) $($(package)_source) | sha256sum -c &&\
|
||||
|
||||
@@ -4,30 +4,16 @@ $(package)_download_path=https://github.com/tpoechtrager/apple-libtapi/archive
|
||||
$(package)_download_file=$($(package)_version).tar.gz
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=62e419c12d1c9fad67cc1cd523132bc00db050998337c734c15bc8d73cc02b61
|
||||
$(package)_build_subdir=build
|
||||
$(package)_dependencies=native_clang
|
||||
$(package)_patches=no_embed_git_rev.patch
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 -i $($(package)_patch_dir)/no_embed_git_rev.patch
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
echo -n $(build_prefix) > INSTALLPREFIX; \
|
||||
CC=$(host_prefix)/native/bin/clang CXX=$(host_prefix)/native/bin/clang++ \
|
||||
cmake -DCMAKE_INSTALL_PREFIX=$(build_prefix) \
|
||||
-DLLVM_INCLUDE_TESTS=OFF \
|
||||
-DCMAKE_BUILD_TYPE=RELEASE \
|
||||
-DTAPI_REPOSITORY_STRING="1100.0.11" \
|
||||
-DTAPI_FULL_VERSION="11.0.0" \
|
||||
-DCMAKE_CXX_FLAGS="-I $($(package)_extract_dir)/src/llvm/projects/clang/include -I $($(package)_build_dir)/projects/clang/include" \
|
||||
$($(package)_extract_dir)/src/llvm
|
||||
endef
|
||||
|
||||
define $(package)_build_cmds
|
||||
$(MAKE) clangBasic && $(MAKE) libtapi
|
||||
CC=$(clang_prog) CXX=$(clangxx_prog) INSTALLPREFIX=$($(package)_staging_prefix_dir) ./build.sh
|
||||
endef
|
||||
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install-libtapi install-tapi-headers
|
||||
./install.sh
|
||||
endef
|
||||
|
||||
@@ -46,6 +46,7 @@ define $(package)_set_vars
|
||||
endef
|
||||
|
||||
define $(package)_preprocess_cmds
|
||||
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . && \
|
||||
cp $($(package)_patch_dir)/fallback.c ncurses
|
||||
endef
|
||||
|
||||
|
||||
@@ -1,38 +1,34 @@
|
||||
packages:=boost openssl zeromq libiconv expat unbound
|
||||
native_packages := native_protobuf
|
||||
packages := boost openssl zeromq unbound sodium protobuf
|
||||
|
||||
# ccache is useless in gitian builds
|
||||
ifneq ($(GITIAN),1)
|
||||
native_packages := native_ccache
|
||||
ifneq ($(host_os),android)
|
||||
packages += libusb
|
||||
endif
|
||||
|
||||
hardware_packages := hidapi protobuf libusb
|
||||
hardware_native_packages := native_protobuf
|
||||
|
||||
android_native_packages = android_ndk
|
||||
android_packages = ncurses readline sodium
|
||||
|
||||
darwin_native_packages = $(hardware_native_packages)
|
||||
darwin_packages = ncurses readline sodium $(hardware_packages)
|
||||
|
||||
# not really native...
|
||||
freebsd_native_packages = freebsd_base
|
||||
freebsd_packages = ncurses readline sodium
|
||||
|
||||
linux_packages = eudev ncurses readline sodium $(hardware_packages)
|
||||
linux_native_packages = $(hardware_native_packages)
|
||||
|
||||
ifeq ($(build_tests),ON)
|
||||
packages += gtest
|
||||
ifneq ($(host_os),freebsd)
|
||||
ifneq ($(host_os),android)
|
||||
packages += hidapi
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(host_arch),riscv64)
|
||||
linux_packages += unwind
|
||||
ifneq ($(host_os),mingw32)
|
||||
packages += ncurses readline
|
||||
endif
|
||||
|
||||
mingw32_packages = icu4c sodium $(hardware_packages)
|
||||
mingw32_native_packages = $(hardware_native_packages)
|
||||
mingw32_native_packages :=
|
||||
mingw32_packages = icu4c libiconv
|
||||
|
||||
linux_native_packages :=
|
||||
linux_packages := eudev
|
||||
|
||||
freebsd_native_packages := freebsd_base
|
||||
freebsd_packages :=
|
||||
|
||||
ifneq ($(build_os),darwin)
|
||||
darwin_native_packages += darwin_sdk native_clang native_cctools native_libtapi
|
||||
darwin_native_packages := darwin_sdk native_clang native_cctools native_libtapi
|
||||
endif
|
||||
darwin_packages :=
|
||||
|
||||
android_native_packages := android_ndk
|
||||
android_packages :=
|
||||
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
package=unbound
|
||||
$(package)_version=1.19.1
|
||||
$(package)_version=1.22.0
|
||||
$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
|
||||
$(package)_file_name=$(package)-$($(package)_version).tar.gz
|
||||
$(package)_sha256_hash=bc1d576f3dd846a0739adc41ffaa702404c6767d2b6082deb9f2f97cbb24a3a9
|
||||
$(package)_dependencies=openssl expat
|
||||
$(package)_patches=disable-glibc-reallocarray.patch
|
||||
|
||||
$(package)_sha256_hash=c5dd1bdef5d5685b2cedb749158dd152c52d44f65529a34ac15cd88d4b1b3d43
|
||||
$(package)_dependencies=openssl
|
||||
$(package)_patches=no-expat.patch
|
||||
|
||||
define $(package)_set_vars
|
||||
$(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix)
|
||||
$(package)_config_opts+=--with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no
|
||||
$(package)_config_opts+=--with-libexpat=no --with-ssl=$(host_prefix) --with-libevent=no
|
||||
$(package)_config_opts+=--without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only
|
||||
$(package)_config_opts_linux=--with-pic
|
||||
$(package)_config_opts_w64=--enable-static-exe --sysconfdir=/etc --prefix=$(host_prefix) --target=$(host_prefix)
|
||||
$(package)_config_opts_x86_64_darwin=ac_cv_func_SHA384_Init=yes
|
||||
$(package)_build_opts_mingw32=LDFLAGS="$($(package)_ldflags) -lpthread"
|
||||
$(package)_cflags_mingw32+="-D_WIN32_WINNT=0x600"
|
||||
endef
|
||||
|
||||
# Remove blobs
|
||||
define $(package)_preprocess_cmds
|
||||
patch -p1 < $($(package)_patch_dir)/disable-glibc-reallocarray.patch &&\
|
||||
autoconf
|
||||
patch -p1 < $($(package)_patch_dir)/no-expat.patch &&\
|
||||
rm configure~ doc/*.odp doc/*.pdf contrib/*.tar.gz contrib/*.tar.bz2 &&\
|
||||
rm -rf testdata dnscrypt/testdata
|
||||
endef
|
||||
|
||||
define $(package)_config_cmds
|
||||
@@ -34,3 +34,7 @@ endef
|
||||
define $(package)_stage_cmds
|
||||
$(MAKE) DESTDIR=$($(package)_staging_dir) install
|
||||
endef
|
||||
|
||||
define $(package)_postprocess_cmds
|
||||
rm -rf share
|
||||
endef
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
--- boost_1_64_0/tools/build/src/tools/darwin.jam.O 2017-04-17 03:22:26.000000000 +0100
|
||||
+++ boost_1_64_0/tools/build/src/tools/darwin.jam 2022-05-04 17:26:29.984464447 +0000
|
||||
@@ -505,7 +505,7 @@
|
||||
if $(instruction-set) {
|
||||
options = -arch$(_)$(instruction-set) ;
|
||||
} else {
|
||||
- options = -arch arm ;
|
||||
+# options = -arch arm ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
--- boost_1_64_0/tools/build/src/tools/gcc.jam.O 2017-04-17 03:22:26.000000000 +0100
|
||||
+++ boost_1_64_0/tools/build/src/tools/gcc.jam 2019-11-15 15:46:16.957937137 +0000
|
||||
@@ -243,6 +243,8 @@
|
||||
{
|
||||
ECHO notice: using gcc archiver :: $(condition) :: $(archiver[1]) ;
|
||||
}
|
||||
+ local arflags = [ feature.get-values <arflags> : $(options) ] ;
|
||||
+ toolset.flags gcc.archive .ARFLAGS $(condition) : $(arflags) ;
|
||||
|
||||
# - Ranlib.
|
||||
local ranlib = [ common.get-invocation-command gcc
|
||||
@@ -970,6 +972,7 @@
|
||||
# logic in intel-linux, but that is hardly worth the trouble as on Linux, 'ar'
|
||||
# is always available.
|
||||
.AR = ar ;
|
||||
+.ARFLAGS = rc ;
|
||||
.RANLIB = ranlib ;
|
||||
|
||||
toolset.flags gcc.archive AROPTIONS <archiveflags> ;
|
||||
@@ -1011,7 +1014,7 @@
|
||||
#
|
||||
actions piecemeal archive
|
||||
{
|
||||
- "$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)"
|
||||
+ "$(.AR)" $(AROPTIONS) $(.ARFLAGS) "$(<)" "$(>)"
|
||||
"$(.RANLIB)" "$(<)"
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 5c7da197..e2b25288 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -1702,6 +1702,9 @@ AC_LINK_IFELSE([AC_LANG_SOURCE(AC_INCLUDES_DEFAULT
|
||||
#ifndef _OPENBSD_SOURCE
|
||||
#define _OPENBSD_SOURCE 1
|
||||
#endif
|
||||
+#ifdef __linux__
|
||||
+# error reallocarray() is currently disabled on Linux to support glibc < 2.26
|
||||
+#endif
|
||||
#include <stdlib.h>
|
||||
int main(void) {
|
||||
void* p = reallocarray(NULL, 10, 100);
|
||||
@@ -0,0 +1,20 @@
|
||||
diff --git a/configure b/configure
|
||||
index a41e3e1e..7d6a58f0 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -22053,6 +22053,7 @@ else $as_nop
|
||||
withval="/usr/local /opt/local /usr/lib /usr/pkg /usr/sfw /usr"
|
||||
fi
|
||||
|
||||
+if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libexpat" >&5
|
||||
printf %s "checking for libexpat... " >&6; }
|
||||
found_libexpat="no"
|
||||
@@ -22090,6 +22091,7 @@ else $as_nop
|
||||
ac_have_decl=0
|
||||
fi
|
||||
printf "%s\n" "#define HAVE_DECL_XML_STOPPARSER $ac_have_decl" >>confdefs.h
|
||||
+fi
|
||||
|
||||
|
||||
# hiredis (redis C client for cachedb)
|
||||
@@ -91,7 +91,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||
SET(BREW OFF)
|
||||
SET(PORT OFF)
|
||||
SET(CMAKE_OSX_SYSROOT "@prefix@/native/SDK/")
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
|
||||
SET(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
|
||||
SET(CMAKE_CXX_STANDARD 17)
|
||||
SET(LLVM_ENABLE_PIC OFF)
|
||||
SET(LLVM_ENABLE_PIE OFF)
|
||||
|
||||
Vendored
+1
-1
Submodule external/mx25519 updated: 42f36ede5f...e808a6406b
@@ -238,7 +238,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair
|
||||
LOG_PRINT_L1("Failed to get output unlock time, aborting transaction addition");
|
||||
throw std::runtime_error("Unexpected error getting output unlock_time, aborting");
|
||||
}
|
||||
if (miner_tx && tx.version == 2)
|
||||
if (miner_tx && tx.version >= 2)
|
||||
{
|
||||
cryptonote::tx_out vout = tx.vout[i];
|
||||
// TODO: avoid multiple expensive zeroCommitVartime call here + get_outs_by_last_locked_block + ver_non_input_consensus
|
||||
|
||||
@@ -207,6 +207,17 @@ typedef struct yield_tx_info {
|
||||
crypto::public_key return_pubkey;
|
||||
} yield_tx_info;
|
||||
|
||||
typedef struct yield_tx_info_carrot {
|
||||
uint64_t block_height;
|
||||
uint8_t version;
|
||||
crypto::hash tx_hash;
|
||||
uint64_t locked_coins;
|
||||
crypto::public_key return_address;
|
||||
crypto::public_key return_pubkey;
|
||||
carrot::view_tag_t return_view_tag;
|
||||
carrot::encrypted_janus_anchor_t return_anchor_enc;
|
||||
} yield_tx_info_carrot;
|
||||
|
||||
#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
|
||||
|
||||
@@ -110,7 +110,7 @@ CarrotDestinationV1 carrot_and_legacy_account::subaddress(const subaddress_index
|
||||
return addr;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> carrot_and_legacy_account::get_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)
|
||||
@@ -120,10 +120,15 @@ std::unordered_map<crypto::public_key, cryptonote::subaddress_index> carrot_and_
|
||||
return res;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
std::unordered_map<crypto::public_key, subaddress_index_extended>& carrot_and_legacy_account::get_subaddress_map_ref() {
|
||||
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,
|
||||
@@ -310,6 +315,27 @@ crypto::secret_key carrot_and_legacy_account::generate(
|
||||
return retval;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::set_keys(const cryptonote::account_keys& keys, bool copy_spend_secret_keys)
|
||||
{
|
||||
// CN keys
|
||||
m_keys.m_account_address = keys.m_account_address;
|
||||
if (copy_spend_secret_keys) m_keys.m_spend_secret_key = keys.m_spend_secret_key;
|
||||
m_keys.m_view_secret_key = keys.m_view_secret_key;
|
||||
if (copy_spend_secret_keys) m_keys.m_multisig_keys = keys.m_multisig_keys;
|
||||
m_keys.m_device = keys.m_device;
|
||||
m_keys.m_encryption_iv = keys.m_encryption_iv;
|
||||
|
||||
// Carrot keys
|
||||
if (copy_spend_secret_keys) m_keys.s_master = keys.s_master;
|
||||
if (copy_spend_secret_keys) m_keys.k_prove_spend = keys.k_prove_spend;
|
||||
m_keys.s_view_balance = keys.s_view_balance;
|
||||
m_keys.k_view_incoming = keys.k_view_incoming;
|
||||
m_keys.k_generate_image = keys.k_generate_image;
|
||||
m_keys.s_generate_address = keys.s_generate_address;
|
||||
m_keys.m_carrot_account_address = keys.m_carrot_account_address;
|
||||
m_keys.m_carrot_main_address = keys.m_carrot_main_address;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
void carrot_and_legacy_account::set_carrot_keys(const AddressDeriveType default_derive_type)
|
||||
{
|
||||
// top level keys
|
||||
@@ -345,7 +371,12 @@ void carrot_and_legacy_account::insert_subaddresses(const std::unordered_map<cry
|
||||
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
|
||||
{
|
||||
@@ -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,6 +43,50 @@ static constexpr std::uint32_t MAX_SUBADDRESS_MINOR_INDEX = 20;
|
||||
|
||||
namespace carrot
|
||||
{
|
||||
|
||||
struct return_output_info_t {
|
||||
input_context_t input_context;
|
||||
crypto::public_key K_o; // output onetime address
|
||||
crypto::public_key K_change; // change output onetime address
|
||||
crypto::key_image key_image;
|
||||
crypto::secret_key x;
|
||||
crypto::secret_key y;
|
||||
|
||||
return_output_info_t() {
|
||||
// Default constructor for serialization
|
||||
input_context = input_context_t();
|
||||
K_o = crypto::public_key();
|
||||
K_change = crypto::public_key();
|
||||
key_image = crypto::key_image();
|
||||
x = crypto::secret_key();
|
||||
y = crypto::secret_key();
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(input_context)
|
||||
FIELD(K_o)
|
||||
FIELD(K_change)
|
||||
FIELD(key_image)
|
||||
FIELD(x)
|
||||
FIELD(y)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
||||
class carrot_and_legacy_account : public cryptonote::account_base
|
||||
{
|
||||
public:
|
||||
@@ -57,6 +101,8 @@ namespace carrot
|
||||
s_generate_address_dev(get_keys().s_generate_address)
|
||||
{}
|
||||
|
||||
void set_keys(const cryptonote::account_keys& keys, bool copy_spend_secret_keys);
|
||||
|
||||
carrot_and_legacy_account(const carrot_and_legacy_account &k) = delete;
|
||||
carrot_and_legacy_account(carrot_and_legacy_account&&) = delete;
|
||||
|
||||
@@ -68,9 +114,10 @@ namespace carrot
|
||||
|
||||
CarrotDestinationV1 subaddress(const subaddress_index_extended &subaddress_index) const;
|
||||
|
||||
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> get_subaddress_map_cn() const;
|
||||
std::unordered_map<crypto::public_key, subaddress_index_extended>& get_subaddress_map_ref();
|
||||
|
||||
const std::unordered_map<crypto::public_key, cryptonote::subaddress_index> get_subaddress_map_cn() const;
|
||||
const std::unordered_map<crypto::public_key, subaddress_index_extended>& get_subaddress_map_ref() const;
|
||||
const std::unordered_map<crypto::public_key, return_output_info_t>& get_return_output_map_ref() const;
|
||||
|
||||
// brief: opening_for_subaddress - return (k^g_a, k^t_a) for j s.t. K^j_s = (k^g_a * G + k^t_a * T)
|
||||
void opening_for_subaddress(const subaddress_index_extended &subaddress_index,
|
||||
crypto::secret_key &address_privkey_g_out,
|
||||
@@ -108,10 +155,47 @@ namespace 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;
|
||||
};
|
||||
}
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
template <class Archive>
|
||||
inline typename std::enable_if<!Archive::is_loading::value, void>::type initialize_transfer_details(Archive &a, carrot::return_output_info_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
}
|
||||
template <class Archive>
|
||||
inline typename std::enable_if<Archive::is_loading::value, void>::type initialize_transfer_details(Archive &a, carrot::return_output_info_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
x.input_context = carrot::input_context_t();
|
||||
x.K_o = crypto::public_key();
|
||||
x.K_change = crypto::public_key();
|
||||
x.key_image = crypto::key_image();
|
||||
x.x = crypto::secret_key();
|
||||
x.y = crypto::secret_key();
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, carrot::return_output_info_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & x.input_context;
|
||||
a & x.K_o;
|
||||
a & x.K_change;
|
||||
a & x.key_image;
|
||||
a & x.x;
|
||||
a & x.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,7 +70,7 @@ 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 = 128;
|
||||
static constexpr const unsigned int CARROT_MAX_TX_INPUTS = 64;
|
||||
|
||||
// SPARC addressing protocol domain separators
|
||||
static constexpr const unsigned char SPARC_DOMAIN_SEP_RETURN_PUBKEY_ENCRYPTION_MASK[] = "SPARC return pubkey encryption mask";
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -159,6 +159,7 @@ 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,
|
||||
@@ -173,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");
|
||||
|
||||
@@ -211,7 +216,7 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
// construct normal enotes
|
||||
for (size_t i = 0; i < normal_payment_proposals.size(); ++i)
|
||||
{
|
||||
auto &output_entry = tools::add_element(sortable_data);
|
||||
auto &output_entry = sortable_data.emplace_back();
|
||||
output_entry.second = {false, i};
|
||||
|
||||
encrypted_payment_id_t encrypted_payment_id;
|
||||
@@ -265,7 +270,7 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
{
|
||||
const CarrotPaymentProposalSelfSendV1 &selfsend_payment_proposal = selfsend_payment_proposals.at(i);
|
||||
|
||||
auto &output_entry = tools::add_element(sortable_data);
|
||||
auto &output_entry = sortable_data.emplace_back();
|
||||
output_entry.second = {true, i};
|
||||
|
||||
if (s_view_balance_dev != nullptr)
|
||||
@@ -274,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)
|
||||
@@ -354,11 +361,11 @@ void get_output_enote_proposals(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
component_out_of_order, "this set contains duplicate onetime addresses");
|
||||
|
||||
// assert all K_o lie in prime order subgroup
|
||||
for (const RCTOutputEnoteProposal &output_enote_proposal : output_enote_proposals_out)
|
||||
{
|
||||
CARROT_CHECK_AND_THROW(rct::isInMainSubgroup(rct::pk2rct(output_enote_proposal.enote.onetime_address)),
|
||||
invalid_point, "this set contains an invalid onetime address");
|
||||
}
|
||||
// for (const RCTOutputEnoteProposal &output_enote_proposal : output_enote_proposals_out)
|
||||
// {
|
||||
// CARROT_CHECK_AND_THROW(rct::isInMainSubgroup(rct::pk2rct(output_enote_proposal.enote.onetime_address)),
|
||||
// invalid_point, "this set contains an invalid onetime address");
|
||||
// }
|
||||
|
||||
// assert unique and non-trivial k_a
|
||||
memcmp_set<crypto::secret_key> amount_blinding_factors;
|
||||
@@ -409,7 +416,7 @@ void get_coinbase_output_enotes(const std::vector<CarrotPaymentProposalV1> &norm
|
||||
{
|
||||
get_coinbase_output_proposal_v1(normal_payment_proposals[i],
|
||||
block_index,
|
||||
tools::add_element(output_coinbase_enotes_out));
|
||||
output_coinbase_enotes_out.emplace_back());
|
||||
}
|
||||
|
||||
// assert uniqueness and non-trivial-ness of D_e
|
||||
|
||||
@@ -109,6 +109,7 @@ 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,
|
||||
|
||||
@@ -179,7 +179,7 @@ static void get_external_output_proposal_parts(const mx25519_pubkey &s_sender_re
|
||||
encrypted_amount_t &encrypted_amount_out,
|
||||
encrypted_payment_id_t &encrypted_payment_id_out,
|
||||
view_tag_t &view_tag_out,
|
||||
encrypted_return_pubkey_t return_pubkey_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,
|
||||
@@ -331,7 +331,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,
|
||||
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,
|
||||
@@ -499,6 +499,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)
|
||||
{
|
||||
// 1. sanity checks
|
||||
@@ -560,6 +562,37 @@ void get_output_proposal_internal_v1(const CarrotPaymentProposalSelfSendV1 &prop
|
||||
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,
|
||||
|
||||
@@ -175,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
|
||||
|
||||
+188
-20
@@ -70,6 +70,104 @@ static crypto::secret_key make_enote_ephemeral_privkey_sender(const janus_anchor
|
||||
return enote_ephemeral_privkey;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
bool scan_return_output(
|
||||
const crypto::public_key &return_onetime_address,
|
||||
const mx25519_pubkey &return_ephemeral_pubkey,
|
||||
const carrot::view_tag_t &return_view_tag,
|
||||
const carrot::encrypted_janus_anchor_t &return_anchor_enc,
|
||||
const carrot::encrypted_amount_t &return_amount_enc,
|
||||
const std::optional<rct::key> amount_commitment,
|
||||
const carrot::input_context_t &return_input_context,
|
||||
carrot::carrot_and_legacy_account &account,
|
||||
crypto::public_key &address_spend_pubkey_out,
|
||||
rct::xmr_amount &amount_out,
|
||||
crypto::secret_key &amount_blinding_factor_out
|
||||
) {
|
||||
const auto &return_output_map = account.get_return_output_map_ref();
|
||||
CHECK_AND_ASSERT_MES(return_output_map.count(return_onetime_address), false, "return output not found");
|
||||
const auto &origin_tx = return_output_map.at(return_onetime_address);
|
||||
|
||||
// 1. make k_return
|
||||
crypto::secret_key k_return;
|
||||
account.s_view_balance_dev.make_internal_return_privkey(origin_tx.input_context, origin_tx.K_o, k_return);
|
||||
|
||||
// 2. compute K_return' = k_return * G
|
||||
crypto::public_key K_return;
|
||||
crypto::secret_key_to_public_key(k_return, K_return);
|
||||
|
||||
// 3. ssr
|
||||
mx25519_pubkey shared_secret_return_unctx;
|
||||
crypto::hash shared_secret_return;
|
||||
carrot::make_carrot_uncontextualized_shared_key_receiver(k_return, return_ephemeral_pubkey, shared_secret_return_unctx);
|
||||
carrot::make_carrot_sender_receiver_secret(
|
||||
shared_secret_return_unctx.data,
|
||||
return_ephemeral_pubkey,
|
||||
return_input_context,
|
||||
shared_secret_return
|
||||
);
|
||||
|
||||
// 4. verify the view_tag
|
||||
CHECK_AND_ASSERT_MES(
|
||||
carrot::test_carrot_view_tag(
|
||||
shared_secret_return_unctx.data,
|
||||
return_input_context,
|
||||
return_onetime_address,
|
||||
return_view_tag
|
||||
),
|
||||
false,
|
||||
"view tag verification failed for carrot coinbase enote"
|
||||
);
|
||||
|
||||
// 5. compute anchor_return
|
||||
carrot::janus_anchor_t recovered_anchor_return =
|
||||
carrot::decrypt_carrot_anchor(return_anchor_enc, shared_secret_return, return_onetime_address);
|
||||
|
||||
// 6. compute d_e'
|
||||
crypto::secret_key recovered_ephemeral_privkey_return;
|
||||
carrot::make_carrot_enote_ephemeral_privkey(
|
||||
recovered_anchor_return,
|
||||
return_input_context,
|
||||
origin_tx.K_change,
|
||||
carrot::null_payment_id,
|
||||
recovered_ephemeral_privkey_return
|
||||
);
|
||||
|
||||
// 7. compute D_e'
|
||||
mx25519_pubkey recovered_ephemeral_pubkey_return;
|
||||
carrot::make_carrot_enote_ephemeral_pubkey(
|
||||
recovered_ephemeral_privkey_return,
|
||||
origin_tx.K_change,
|
||||
false,
|
||||
recovered_ephemeral_pubkey_return
|
||||
);
|
||||
|
||||
// 8. verify the enote ephemeral pubkey
|
||||
CHECK_AND_ASSERT_MES(
|
||||
memcmp(recovered_ephemeral_pubkey_return.data, return_ephemeral_pubkey.data, sizeof(mx25519_pubkey)) == 0,
|
||||
false,
|
||||
"carrot coinbase enote protection verification failed"
|
||||
);
|
||||
|
||||
amount_out = carrot::decrypt_carrot_amount(return_amount_enc, shared_secret_return, return_onetime_address);
|
||||
address_spend_pubkey_out = origin_tx.K_change;
|
||||
|
||||
if (amount_commitment)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(
|
||||
carrot::try_recompute_carrot_amount_commitment(shared_secret_return,
|
||||
amount_out,
|
||||
address_spend_pubkey_out,
|
||||
carrot::CarrotEnoteType::PAYMENT,
|
||||
amount_commitment.value(),
|
||||
amount_blinding_factor_out
|
||||
),
|
||||
false,
|
||||
"failed to recompute carrot amount commitment for return output"
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
static bool try_scan_carrot_coinbase_enote_checked(
|
||||
const CarrotCoinbaseEnoteV1 &enote,
|
||||
const mx25519_pubkey &s_sender_receiver_unctx,
|
||||
@@ -361,43 +459,113 @@ 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);
|
||||
|
||||
// compute K_return = k_return * G
|
||||
crypto::public_key K_return;
|
||||
crypto::secret_key_to_public_key(k_return, K_return);
|
||||
|
||||
// compute K_r = K_return + K_o
|
||||
crypto::public_key K_r = rct::rct2pk(rct::addKeys(rct::pk2rct(K_return), rct::pk2rct(enote.onetime_address)));
|
||||
|
||||
// calculate the key image for the return output
|
||||
crypto::secret_key sum_g;
|
||||
sc_add(to_bytes(sum_g), to_bytes(sender_extension_g_out), to_bytes(k_return));
|
||||
crypto::key_image key_image = account.derive_key_image(
|
||||
account.get_keys().m_carrot_account_address.m_spend_public_key,
|
||||
sum_g,
|
||||
sender_extension_t_out,
|
||||
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,
|
||||
sender_extension_t_out,
|
||||
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
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "carrot_core/enote_utils.h"
|
||||
#include "carrot_core/exceptions.h"
|
||||
#include "carrot_core/payment_proposal.h"
|
||||
#include "common/container_helpers.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/cryptonote_tx_utils.h"
|
||||
#include "cryptonote_config.h"
|
||||
@@ -198,7 +197,9 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
const std::vector<cryptonote::tx_source_entry> &sources,
|
||||
const rct::xmr_amount fee,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const std::vector<uint8_t> change_masks,
|
||||
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();
|
||||
@@ -208,11 +209,15 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
|
||||
cryptonote::transaction tx;
|
||||
tx.pruned = true;
|
||||
tx.version = TRANSACTION_VERSION_N_OUTS;
|
||||
tx.unlock_time = 0;
|
||||
tx.source_asset_type = "SAL1";
|
||||
tx.destination_asset_type = "SAL1";
|
||||
tx.type = tx_type == cryptonote::transaction_type::RETURN ? cryptonote::transaction_type::TRANSFER : tx_type;
|
||||
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);
|
||||
@@ -252,16 +257,28 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
}});
|
||||
|
||||
//a_enc
|
||||
rct::ecdhTuple &ecdh_tuple = tools::add_element(tx.rct_signatures.ecdhInfo);
|
||||
rct::ecdhTuple &ecdh_tuple = tx.rct_signatures.ecdhInfo.emplace_back();
|
||||
memcpy(ecdh_tuple.amount.bytes, enote.amount_enc.bytes, sizeof(ecdh_tuple.amount));
|
||||
|
||||
//C_a
|
||||
tx.rct_signatures.outPk.push_back(rct::ctkey{rct::key{}, enote.amount_commitment});
|
||||
|
||||
//K_return
|
||||
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);
|
||||
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
|
||||
@@ -337,6 +354,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;
|
||||
}
|
||||
@@ -395,7 +420,7 @@ cryptonote::transaction store_carrot_to_coinbase_transaction_v1(
|
||||
cryptonote::transaction tx;
|
||||
tx.type = tx_type;
|
||||
tx.pruned = false;
|
||||
tx.version = 2;
|
||||
tx.version = TRANSACTION_VERSION_CARROT;
|
||||
tx.unlock_time = CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
tx.vin.reserve(1);
|
||||
tx.vout.reserve(nouts);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/tx_extra.h"
|
||||
#include "cryptonote_core/cryptonote_tx_utils.h"
|
||||
#include "carrot_core/payment_proposal.h"
|
||||
|
||||
//third party headers
|
||||
|
||||
@@ -105,7 +106,9 @@ cryptonote::transaction store_carrot_to_transaction_v1(const std::vector<CarrotE
|
||||
const std::vector<cryptonote::tx_source_entry> &sources,
|
||||
const rct::xmr_amount fee,
|
||||
const cryptonote::transaction_type tx_type,
|
||||
const std::vector<uint8_t> change_masks,
|
||||
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
|
||||
|
||||
@@ -318,33 +318,27 @@ std::vector<std::size_t> get_input_counts_in_preferred_order()
|
||||
// 1 or 2 randomly, then
|
||||
// other ascending powers of 2, then
|
||||
// other ascending positive numbers
|
||||
|
||||
|
||||
//! @TODO: MRL discussion about 2 vs 1 default input count when 1 input can pay. If we default
|
||||
// to 1, then that may reveal more information about the amount, and reveals that one can't pay
|
||||
// with 1 output when using 2. Vice versa, if we default to 2, then that means that one only
|
||||
// owns 1 output when using 1. It may be the most advantageous to randomly switch between
|
||||
// preferring 1 vs 2. See: https://lavalle.pl/planning/node437.html. Con to this approach: if we
|
||||
// default to 1 over 2 always then there's scenarios where we net save tx fees and proving time.
|
||||
|
||||
//static_assert(CARROT_MAX_TX_INPUTS == FCMP_PLUS_PLUS_MAX_INPUTS, "inconsistent input count max limit");
|
||||
static_assert(CARROT_MIN_TX_INPUTS == 1 && CARROT_MAX_TX_INPUTS == 128,
|
||||
// preferring 1 vs 2. See: https://lavalle.pl/planning/node437.html. Con to this approach: if we
|
||||
// default to 1 over 2 always then there's scenarios where we net save tx fees and proving time.
|
||||
|
||||
//static_assert(CARROT_MAX_TX_INPUTS == FCMP_PLUS_PLUS_MAX_INPUTS, "inconsistent input count max limit");
|
||||
static_assert(CARROT_MIN_TX_INPUTS == 1 && CARROT_MAX_TX_INPUTS == 64,
|
||||
"refactor this function for different input count limits");
|
||||
|
||||
const bool random_bit = 0 == (crypto::rand<uint8_t>() & 0x01);
|
||||
if (random_bit)
|
||||
return {2, 1, 4, 8, 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};
|
||||
return {2, 1, 4, 8, 16, 32, 64, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
|
||||
else
|
||||
return {1, 2, 4, 8, 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};
|
||||
return {1, 2, 4, 8, 16, 32, 64, 3, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23,
|
||||
24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63};
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
select_inputs_func_t make_single_transfer_input_selector(
|
||||
|
||||
@@ -60,6 +60,7 @@ 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,
|
||||
@@ -68,6 +69,7 @@ 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,
|
||||
@@ -127,7 +129,9 @@ void make_pruned_transaction_from_proposal_v1(const CarrotTransactionProposalV1
|
||||
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
|
||||
|
||||
@@ -86,6 +86,8 @@ struct CarrotTransactionProposalV1
|
||||
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);
|
||||
@@ -217,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());
|
||||
@@ -273,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,
|
||||
@@ -382,6 +394,16 @@ void make_carrot_transaction_proposal_v1_transfer(
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(fee_remainder == 0,
|
||||
"make unsigned transaction transfer subtractable: bug: fee remainder at end of carve function");
|
||||
|
||||
// remove the self send payment we have made to ourself now that we have our change payment.
|
||||
if (tx_type == cryptonote::transaction_type::STAKE ||
|
||||
tx_type == cryptonote::transaction_type::BURN)
|
||||
{
|
||||
selfsend_payment_proposals.back().proposal.enote_ephemeral_pubkey =
|
||||
selfsend_payment_proposals.front().proposal.enote_ephemeral_pubkey;
|
||||
selfsend_payment_proposals.erase(selfsend_payment_proposals.begin());
|
||||
}
|
||||
|
||||
}; //end carve_fees_and_balance
|
||||
|
||||
// make unsigned transaction with fee carving callback
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -138,13 +138,6 @@ bool keys_match_internal_values(const std::unordered_map<KeyT, ValueT> &map, Pre
|
||||
|
||||
return true;
|
||||
}
|
||||
/// convenience wrapper for getting the last element after emplacing back
|
||||
template <typename ContainerT>
|
||||
typename ContainerT::value_type& add_element(ContainerT &container)
|
||||
{
|
||||
container.emplace_back();
|
||||
return container.back();
|
||||
}
|
||||
/// convenience erasor for unordered maps: std::erase_if(std::unordered_map) is C++20
|
||||
template <typename KeyT, typename ValueT, typename PredT>
|
||||
void for_all_in_map_erase_if(std::unordered_map<KeyT, ValueT> &map_inout, PredT predicate)
|
||||
|
||||
@@ -151,6 +151,8 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
void account_base::forget_spend_key()
|
||||
{
|
||||
m_keys.m_spend_secret_key = crypto::secret_key();
|
||||
m_keys.s_master = m_keys.m_spend_secret_key;
|
||||
m_keys.k_prove_spend = m_keys.m_spend_secret_key;
|
||||
m_keys.m_multisig_keys.clear();
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
@@ -163,6 +165,7 @@ DISABLE_VS_WARNINGS(4244 4345)
|
||||
"Unexpected derived public spend key");
|
||||
|
||||
m_keys.m_spend_secret_key = spend_secret_key;
|
||||
m_keys.s_master = m_keys.m_spend_secret_key;
|
||||
}
|
||||
//-----------------------------------------------------------------
|
||||
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -285,6 +285,8 @@ namespace cryptonote {
|
||||
LOG_PRINT_L1("Failed to validate address keys");
|
||||
return false;
|
||||
}
|
||||
|
||||
info.address.m_is_carrot = info.is_carrot;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -316,6 +318,7 @@ 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;
|
||||
|
||||
@@ -73,6 +73,11 @@ namespace boost
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, carrot::input_context_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(carrot::input_context_t)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::view_tag &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::view_tag)]>(x);
|
||||
@@ -166,6 +171,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 +197,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 +229,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();
|
||||
@@ -1383,7 +1383,7 @@ namespace cryptonote
|
||||
{
|
||||
if (hf_version >= HF_VERSION_CARROT)
|
||||
{
|
||||
// from v11, require outputs be carrot outputs
|
||||
// from v10, require outputs be carrot outputs
|
||||
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
|
||||
<< o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx));
|
||||
} else {
|
||||
|
||||
@@ -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;
|
||||
|
||||
+19
-18
@@ -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
|
||||
@@ -249,7 +250,7 @@
|
||||
#define HF_VERSION_ENABLE_ORACLE 255
|
||||
#define HF_VERSION_SLIPPAGE_YIELD 255
|
||||
|
||||
#define TESTNET_VERSION 14
|
||||
#define TESTNET_VERSION 15
|
||||
#define STAGENET_VERSION 1
|
||||
|
||||
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
|
||||
@@ -430,22 +431,22 @@ namespace config
|
||||
|
||||
// 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"}}
|
||||
{1100, {"0d82afb3ae9c5de25a06da49e24e64d37ba05d6144f9f6153cea325c61407106","81440913c1484891d25010986806a62d1fae1b2fe045e3ac1396413638d594f1","40864bbf80397c05516368a1397eb5c3","220bda"}},
|
||||
{1120, {"a032f2de4d3b5d880d3a636d9786a4a2f586bee360c323bc7521f987a2ada51b","cf8e5eeb5d37996d86c9c4c88fabaabc1ec77bab9cd5ce610a61b49f1e079ce2","9877a989e0216f76a8cdf0a568e57d45","017549"}},
|
||||
{1140, {"51da7a4c34aa20a800ada615a931fbba5fd1b9f7df78f0f911097ad9d99dc230","dd784a5bf1adf9c01cb44946ca094ed4d38f8d9cccf8edfdab397db3b7631dbf","97314be452f184b54f16a558ee8a7dbe","357ac3"}},
|
||||
{1160, {"a0cf49118c62cea834fabae83e12f26939ce170f308adadacf7275226e5cdf6d","7ec9cb2dfac8dfa45bab1bab2b1e31a4291a9e3d939e9c193740cc191d1b720d","4e950acc71ffd4f3835ec79202dc46fd","e7da3a"}},
|
||||
{1180, {"5193e35f6cd3ff8408a442be5eaf4aa1871419ecb0c485546e9d995c4c9c2730","39fb9792b88290b3377036a150a6681334ebe5cb201e2005d2c1d7b212b3df4d","cb458163806a277c7b3513df0d5b0028","1939b5"}},
|
||||
{1200, {"a2c71a7381bc48576f4cb4313cb6264d2a6e82cd2ddcbbd5460bce1db8d5021e","d0c46f29f4bbdd5538d64a438c0ab93cb0586e67fbfc7d1671f0c9809d6a7fac","af38cc2ddccb9229728ef704e360e15a","8a8dc1"}},
|
||||
{1220, {"8358105081510e907c98da59636eef777460513d827aba400efbb81d82aead4c","b2b8e2f9bb13e7527d0ee1bc3ebf0ca5057139ee4f9302251455b9f27dca3b16","dc226161830e952b2533fe34b1dd3c48","fb7c67"}},
|
||||
{1240, {"90b0bc153b97a93eefd59af9b47d26c0c91aadda6203de91a15f2f76fc949074","06e6a11b8742ee78beafe89f894fb9078a514ee6dd4e099182ac982ead37eacc","4fbfd0f3c2b8d514f2c675b37b9f0b6f","3308ad"}},
|
||||
{1260, {"cd10148b3175804b17e3c68a6a5556364d585dee89953904b32f005a5f6d8f14","d9d6f64119776e9c97fe2fb540cdb5f40bea0c40127fda0f1f2b831cb7fa7d2b","9c21b83d29324e2d91774a623219ae28","1d647c"}},
|
||||
{1280, {"5963697782de7db5111d12c853f3fec0dd53f597d80cc376c7945f1d4afa224b","cc5e5b1273c10016dc855ec1d9bfa0bcf4736a748125f5341717ad9d080fbba0","19dd1f9a0cac118564e2ccb9f36be53a","7ab2c2"}},
|
||||
{1300, {"cf1d4d2d21b7b3f1a54889e0688a4654687e28a302a2ac3ad046ac2ad323f97a","5b5926da5e9199f190e86073ebd09ccb867faf1e9887c9e52a47c194915b2575","5775fa47af3c7226f2ec3017470410c9","2b03b3"}},
|
||||
{1320, {"b565ec8842f3e6c22c7a23eb23f0e5684b462d2261681dff7b2ce71ab02ff170","4f94cf4d811574c9fcc27888cc972ebc6c01ae97146b9882d397b77c9232d1fd","9d142686627c918a26b6c6853b911143","685b18"}},
|
||||
{1340, {"50d1b1bcacf36ba14b23b3827e36a02a7610dd3199a9f1b9d0a23ebcbd1c2d54","38818e41cf0ce7d54391978801c58087ddd5fe517dadb5e61d840f27a7a81a52","55328f4bff5120d44c5d76fc5a9dfdbd","d17be2"}},
|
||||
{1360, {"7657bf97a9be9beac5f999a1e2c1226613849c41c12df5d7185d4d6613a27328","63d96a47f29fab0e727d13905cc843df40ccb76b14dc48857d0dd9ec0873e8c5","ab4f7ffa6431452f0fac7eec33e89e3e","5acd14"}},
|
||||
{1380, {"845e4cbe9b9d2462fae2225da698d6a4e18340f06b312545ee9cfda8127abd41","cc65f1f22f863b31f3c4a53ac3987186c2a699f387a2bf08d8dfed54037912c6","bda3aa3bdd2b42e8183c1013e4350c98","d4a418"}},
|
||||
{1400, {"4b11413fcba49df61537427ff35fdd47ee12a8467751236ff22681bbea343d2c","32d22bba59559489f422298ae653ef55ec8c87e8705daf4c89da7187c8574cbd","8868e1c1d788ce4560beb4afbe77aa5a","5a35d9"}}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1348,6 +1348,11 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height,
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "coinbase transaction in the block has the wrong type");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.version > 1, false, "Invalid coinbase transaction version");
|
||||
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.version == TRANSACTION_VERSION_CARROT, false, "miner transaction has wrong version");
|
||||
CHECK_AND_ASSERT_MES(b.miner_tx.type == cryptonote::transaction_type::MINER, false, "miner transaction has wrong type");
|
||||
}
|
||||
|
||||
// for v2 txes (ringct), we only accept empty rct signatures for miner transactions,
|
||||
if (hf_version >= HF_VERSION_REJECT_SIGS_IN_COINBASE && b.miner_tx.version >= 2)
|
||||
{
|
||||
@@ -1398,6 +1403,11 @@ bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t heigh
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.vin[0].type() == typeid(txin_gen), false, "coinbase protocol transaction in the block has the wrong type");
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.version > 1, false, "Invalid coinbase protocol transaction version");
|
||||
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.version == TRANSACTION_VERSION_CARROT, false, "protocol transaction has wrong version");
|
||||
CHECK_AND_ASSERT_MES(b.protocol_tx.type == cryptonote::transaction_type::PROTOCOL, false, "protocol transaction has wrong type");
|
||||
}
|
||||
|
||||
// for v2 txes (ringct), we only accept empty rct signatures for protocol transactions,
|
||||
if (hf_version >= HF_VERSION_REJECT_SIGS_IN_COINBASE && b.protocol_tx.version >= 2)
|
||||
{
|
||||
@@ -1427,8 +1437,8 @@ std::tuple<bool, size_t> Blockchain::validate_treasury_payout(const transaction&
|
||||
|
||||
// find the treasury output
|
||||
const auto [tx_key, onetime_address, anchor_enc, viewtag] = treasury_data;
|
||||
//const auto expected_output_key = std::get<1>(treasury_output_data);
|
||||
const auto &output = std::find_if(tx.vout.begin(), tx.vout.end(), [&onetime_address](const tx_out &o) {
|
||||
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_carrot_v1)) {
|
||||
output_key = epee::string_tools::pod_to_hex(boost::get<txout_to_carrot_v1>(o.target).key);
|
||||
@@ -1436,7 +1446,7 @@ std::tuple<bool, size_t> Blockchain::validate_treasury_payout(const transaction&
|
||||
return false;
|
||||
}
|
||||
|
||||
return output_key == onetime_address;
|
||||
return output_key == oa;
|
||||
});
|
||||
|
||||
if (output == tx.vout.end()) {
|
||||
@@ -1563,6 +1573,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) {
|
||||
@@ -1571,10 +1582,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1607,7 +1625,56 @@ 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) {
|
||||
|
||||
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 return pubkey
|
||||
if (b.protocol_tx.vout.size() > 1) {
|
||||
const auto additional_pubkeys = cryptonote::get_additional_tx_pub_keys_from_extra(b.protocol_tx.extra);
|
||||
CHECK_AND_ASSERT_MES(additional_pubkeys.size() > output_idx, false, "Missing return pubkey detected in protocol_tx");
|
||||
CHECK_AND_ASSERT_MES(additional_pubkeys[output_idx] == it->first.return_pubkey, false, "Incorrect return pubkey detected in protocol_tx");
|
||||
} else {
|
||||
const auto main_pubkey = cryptonote::get_tx_pub_key_from_extra(b.protocol_tx.extra);
|
||||
CHECK_AND_ASSERT_MES(main_pubkey == it->first.return_pubkey, false, "Incorrect return pubkey 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);
|
||||
CHECK_AND_ASSERT_MES(out_asset_type == "SAL1", false, "Incorrect output asset_type (!= SAL1) detected in protocol_tx");
|
||||
|
||||
// Verify the view tag
|
||||
CHECK_AND_ASSERT_MES(
|
||||
boost::get<cryptonote::txout_to_carrot_v1>(
|
||||
b.protocol_tx.vout[output_idx].target
|
||||
).view_tag == it->first.return_view_tag, false, "Incorrect view tag detected in protocol_tx"
|
||||
);
|
||||
|
||||
// Verify the anchor encrypted
|
||||
CHECK_AND_ASSERT_MES(
|
||||
boost::get<cryptonote::txout_to_carrot_v1>(
|
||||
b.protocol_tx.vout[output_idx].target
|
||||
).encrypted_janus_anchor == it->first.return_anchor_enc, false, "Incorrect anchor 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};
|
||||
@@ -1866,6 +1933,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
|
||||
@@ -1908,33 +1984,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2355,7 +2462,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;
|
||||
}
|
||||
@@ -3608,7 +3715,7 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
|
||||
*/
|
||||
|
||||
if (hf_version >= HF_VERSION_CARROT) {
|
||||
// from v11, force the new SalviumOne RCT data
|
||||
// from v10, 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));
|
||||
@@ -3691,7 +3798,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;
|
||||
@@ -3699,6 +3806,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) {
|
||||
@@ -3742,7 +3857,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;
|
||||
|
||||
@@ -3941,14 +4056,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)
|
||||
{
|
||||
@@ -4582,6 +4689,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
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -346,10 +346,8 @@ namespace cryptonote
|
||||
|
||||
// Clear the TX contents
|
||||
tx.set_null();
|
||||
tx.type = cryptonote::transaction_type::PROTOCOL;
|
||||
|
||||
// Force the TX type to 2
|
||||
tx.version = 2;
|
||||
tx.type = cryptonote::transaction_type::PROTOCOL;
|
||||
|
||||
const bool do_carrot = hard_fork_version >= HF_VERSION_CARROT;
|
||||
if (do_carrot)
|
||||
@@ -362,29 +360,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -733,9 +733,9 @@ namespace nodetool
|
||||
std::set<std::string> full_addrs;
|
||||
if (m_nettype == cryptonote::TESTNET)
|
||||
{
|
||||
full_addrs.insert("72.5.43.63:29080");
|
||||
full_addrs.insert("195.85.114.217:29080");
|
||||
full_addrs.insert("206.188.197.72:29080");
|
||||
full_addrs.insert("165.22.6.67:29080");
|
||||
full_addrs.insert("165.22.15.162:29080");
|
||||
full_addrs.insert("162.243.163.207:29080");
|
||||
}
|
||||
else if (m_nettype == cryptonote::STAGENET)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/hash.h"
|
||||
#include "mx25519.h"
|
||||
#include "carrot_core/core_types.h"
|
||||
|
||||
// read
|
||||
template <template <bool> class Archive>
|
||||
@@ -85,6 +86,7 @@ BLOB_SERIALIZER(crypto::public_key);
|
||||
BLOB_SERIALIZER(crypto::secret_key);
|
||||
BLOB_SERIALIZER(crypto::key_derivation);
|
||||
BLOB_SERIALIZER(crypto::key_image);
|
||||
BLOB_SERIALIZER(carrot::input_context_t);
|
||||
BLOB_SERIALIZER(crypto::signature);
|
||||
BLOB_SERIALIZER(crypto::view_tag);
|
||||
BLOB_SERIALIZER(crypto::ec_point);
|
||||
@@ -95,6 +97,7 @@ VARIANT_TAG(debug_archive, crypto::public_key, "public_key");
|
||||
VARIANT_TAG(debug_archive, crypto::secret_key, "secret_key");
|
||||
VARIANT_TAG(debug_archive, crypto::key_derivation, "key_derivation");
|
||||
VARIANT_TAG(debug_archive, crypto::key_image, "key_image");
|
||||
VARIANT_TAG(debug_archive, carrot::input_context_t, "input_context");
|
||||
VARIANT_TAG(debug_archive, crypto::signature, "signature");
|
||||
VARIANT_TAG(debug_archive, crypto::view_tag, "view_tag");
|
||||
VARIANT_TAG(debug_archive, crypto::ec_point, "ec_point");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -868,12 +868,21 @@ bool simple_wallet::carrot_keys(const std::vector<std::string> &args/* = std::ve
|
||||
printf("master secret: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().s_master);
|
||||
putchar('\n');
|
||||
printf("view-received secret: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().m_view_secret_key);
|
||||
printf("prove-spend key: ");
|
||||
print_secret_key(m_wallet->get_account().get_keys().k_prove_spend);
|
||||
putchar('\n');
|
||||
printf("view-all secret: ");
|
||||
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;
|
||||
@@ -894,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;
|
||||
}
|
||||
@@ -917,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;
|
||||
}
|
||||
@@ -5227,16 +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 legacy 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_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);
|
||||
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);
|
||||
@@ -5473,11 +5485,11 @@ 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 legacy 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 = tr("Opened carrot wallet");
|
||||
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()) {
|
||||
@@ -6374,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);
|
||||
@@ -6397,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);
|
||||
}
|
||||
@@ -7690,7 +7705,6 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
|
||||
bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_)
|
||||
{
|
||||
CHECK_IF_BACKGROUND_SYNCING("cannot sweep");
|
||||
std::string asset_type = (args_.size() > 1) ? args_.back() : (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) ? "SAL1" : "SAL";
|
||||
auto print_usage = [this, account, below]()
|
||||
{
|
||||
if (below)
|
||||
@@ -7823,6 +7837,8 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
|
||||
}
|
||||
}
|
||||
|
||||
std::string asset_type = (m_wallet->get_current_hard_fork() >= HF_VERSION_SALVIUM_ONE_PROOFS) ? "SAL1" : "SAL";
|
||||
|
||||
std::vector<uint8_t> extra;
|
||||
bool payment_id_seen = false;
|
||||
if (local_args.size() >= 2)
|
||||
@@ -7914,8 +7930,8 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co
|
||||
prompt << tr("WARNING: Outputs of multiple addresses are being used together, which might potentially compromise your privacy.\n");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (ptx_vector.size() > 1) {
|
||||
prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) %
|
||||
@@ -8843,29 +8859,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);
|
||||
@@ -10803,15 +10821,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;
|
||||
@@ -11058,7 +11077,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
|
||||
description += " ";
|
||||
description += args[i];
|
||||
}
|
||||
m_wallet->add_address_book_row(info.address, info.has_payment_id ? &info.payment_id : NULL, description, info.is_subaddress);
|
||||
m_wallet->add_address_book_row(info.address, info.has_payment_id ? &info.payment_id : NULL, description, info.is_subaddress, info.is_carrot);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -11082,9 +11101,9 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
|
||||
success_msg_writer() << tr("Index: ") << i;
|
||||
std::string address;
|
||||
if (row.m_has_payment_id)
|
||||
address = cryptonote::get_account_integrated_address_as_str(m_wallet->nettype(), row.m_address, row.m_payment_id);
|
||||
address = cryptonote::get_account_integrated_address_as_str(m_wallet->nettype(), row.m_address, row.m_payment_id, row.m_is_carrot);
|
||||
else
|
||||
address = get_account_address_as_str(m_wallet->nettype(), row.m_is_subaddress, row.m_address);
|
||||
address = get_account_address_as_str(m_wallet->nettype(), row.m_is_subaddress, row.m_address, row.m_is_carrot);
|
||||
success_msg_writer() << tr("Address: ") << address;
|
||||
success_msg_writer() << tr("Description: ") << row.m_description << "\n";
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
|
||||
#define DEF_SALVIUM_VERSION "0.9.9-rc4"
|
||||
#define DEF_SALVIUM_VERSION "1.0.0-rc2"
|
||||
#define DEF_MONERO_VERSION_TAG "release"
|
||||
#define DEF_MONERO_VERSION "0.18.3.4"
|
||||
#define DEF_MONERO_RELEASE_NAME "One"
|
||||
|
||||
@@ -62,7 +62,7 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa
|
||||
return false;
|
||||
}
|
||||
|
||||
bool r = m_wallet->m_wallet->add_address_book_row(info.address, info.has_payment_id ? &info.payment_id : NULL,description,info.is_subaddress);
|
||||
bool r = m_wallet->m_wallet->add_address_book_row(info.address, info.has_payment_id ? &info.payment_id : NULL,description,info.is_subaddress,info.is_carrot);
|
||||
if (r)
|
||||
refresh();
|
||||
else
|
||||
@@ -81,7 +81,7 @@ bool AddressBookImpl::setDescription(std::size_t index, const std::string &descr
|
||||
|
||||
tools::wallet2::address_book_row entry = ab[index];
|
||||
entry.m_description = description;
|
||||
bool r = m_wallet->m_wallet->set_address_book_row(index, entry.m_address, entry.m_has_payment_id ? &entry.m_payment_id : nullptr, entry.m_description, entry.m_is_subaddress);
|
||||
bool r = m_wallet->m_wallet->set_address_book_row(index, entry.m_address, entry.m_has_payment_id ? &entry.m_payment_id : nullptr, entry.m_description, entry.m_is_subaddress,entry.m_is_carrot);
|
||||
if (r)
|
||||
refresh();
|
||||
else
|
||||
|
||||
+106
-32
@@ -36,7 +36,6 @@
|
||||
#include "carrot_core/lazy_amount_commitment.h"
|
||||
#include "carrot_core/scan.h"
|
||||
#include "carrot_impl/format_utils.h"
|
||||
#include "common/container_helpers.h"
|
||||
#include "crypto/generators.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "ringct/rctOps.h"
|
||||
@@ -133,6 +132,9 @@ static bool try_load_pre_carrot_enote(const bool is_coinbase,
|
||||
enote_out.amount_commitment = rct::Z;
|
||||
}
|
||||
|
||||
// Check for protocol_tx outputs
|
||||
enote_out.is_protocol_tx_output = (tx.type == cryptonote::transaction_type::PROTOCOL);
|
||||
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -169,8 +171,8 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_pre_car
|
||||
|
||||
crypto::ec_scalar amount_key;
|
||||
if (!hwdev.derivation_to_scalar(receive_info->derivation,
|
||||
enote.local_output_index,
|
||||
amount_key))
|
||||
enote.is_protocol_tx_output ? 0 : enote.local_output_index,
|
||||
amount_key))
|
||||
return std::nullopt;
|
||||
|
||||
// a
|
||||
@@ -209,16 +211,16 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_pre_car
|
||||
// derive k^g_o
|
||||
crypto::secret_key sender_extension_g;
|
||||
if (!hwdev.derivation_to_scalar(receive_info->derivation,
|
||||
enote.local_output_index,
|
||||
sender_extension_g))
|
||||
enote.is_protocol_tx_output ? 0 : enote.local_output_index,
|
||||
sender_extension_g))
|
||||
return std::nullopt;
|
||||
|
||||
// K^j_s'
|
||||
crypto::public_key address_spend_pubkey;
|
||||
if (!hwdev.derive_subaddress_public_key(enote.onetime_address,
|
||||
receive_info->derivation,
|
||||
enote.local_output_index,
|
||||
address_spend_pubkey))
|
||||
receive_info->derivation,
|
||||
enote.is_protocol_tx_output ? 0 : enote.local_output_index,
|
||||
address_spend_pubkey))
|
||||
return std::nullopt;
|
||||
|
||||
//pid
|
||||
@@ -235,13 +237,14 @@ 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
|
||||
};
|
||||
|
||||
// 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.get_subaddress_map_ref().insert({enote.onetime_address, subaddr_index});
|
||||
account.insert_subaddresses({{enote.onetime_address, subaddr_index}});
|
||||
// LAND AHOY!!!
|
||||
|
||||
return enote_view_incoming_scan_info_t{
|
||||
@@ -254,26 +257,66 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_pre_car
|
||||
.amount_blinding_factor = amount_blinding_factor,
|
||||
.asset_type = enote.asset_type,
|
||||
.main_tx_pubkey_index = main_deriv_idx,
|
||||
.is_carrot = false
|
||||
.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;
|
||||
@@ -325,6 +368,7 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
res.main_tx_pubkey_index = 0;
|
||||
res.asset_type = enote.asset_type;
|
||||
res.is_carrot = true;
|
||||
res.is_return = false;
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -343,9 +387,13 @@ static std::optional<enote_view_incoming_scan_info_t> view_incoming_scan_carrot_
|
||||
{
|
||||
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,
|
||||
@@ -358,20 +406,38 @@ 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 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");
|
||||
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;
|
||||
|
||||
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;
|
||||
@@ -423,14 +489,14 @@ void perform_ecdh_derivations(const epee::span<const crypto::public_key> main_tx
|
||||
{
|
||||
hwdev.generate_key_derivation(main_tx_ephemeral_pubkey,
|
||||
k_view_incoming,
|
||||
tools::add_element(main_derivations_out));
|
||||
main_derivations_out.emplace_back());
|
||||
}
|
||||
|
||||
for (const crypto::public_key &additional_tx_ephemeral_pubkey : additional_tx_ephemeral_pubkeys)
|
||||
{
|
||||
hwdev.generate_key_derivation(additional_tx_ephemeral_pubkey,
|
||||
k_view_incoming,
|
||||
tools::add_element(additional_derivations_out));
|
||||
additional_derivations_out.emplace_back());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -515,7 +581,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
|
||||
@@ -826,7 +893,7 @@ std::vector<std::optional<enote_view_incoming_scan_info_t>> view_incoming_scan_t
|
||||
// 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.get_subaddress_map_ref()[address.m_spend_public_key] = {{}};
|
||||
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];
|
||||
@@ -859,10 +926,17 @@ 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 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())
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
//local headers
|
||||
#include "carrot_core/carrot_enote_types.h"
|
||||
#include "carrot_core/device.h"
|
||||
#include "carrot_impl/account.h"
|
||||
#include "carrot_core/account.h"
|
||||
#include "carrot_impl/subaddress_index.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
@@ -78,6 +78,12 @@ struct enote_view_incoming_scan_info_t
|
||||
|
||||
// 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
|
||||
@@ -94,6 +100,8 @@ struct PreCarrotEnote
|
||||
bool short_amount;
|
||||
rct::key amount_commitment;
|
||||
rct::ecdhTuple amount;
|
||||
|
||||
bool is_protocol_tx_output;
|
||||
};
|
||||
|
||||
using MoneroEnoteVariant = std::variant<PreCarrotEnote,
|
||||
|
||||
+120
-91
@@ -184,7 +184,7 @@ static crypto::public_key find_change_address_spend_pubkey(
|
||||
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 subaddress map is malformed!!! At least two spend pubkeys map to "
|
||||
"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;
|
||||
@@ -541,9 +541,6 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
const std::set<uint32_t> &subaddr_indices,
|
||||
const wallet2::unique_index_container &subtract_fee_from_outputs)
|
||||
{
|
||||
wallet2::transfer_container transfers;
|
||||
w.get_transfers(transfers);
|
||||
|
||||
const bool use_per_byte_fee = w.use_fork_rules(HF_VERSION_PER_BYTE_FEE, 0);
|
||||
CHECK_AND_ASSERT_THROW_MES(use_per_byte_fee,
|
||||
"make_carrot_transaction_proposals_wallet2_transfer: not using per-byte base fee");
|
||||
@@ -590,7 +587,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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
|
||||
@@ -636,11 +633,11 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
|| (!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)
|
||||
@@ -650,7 +647,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)
|
||||
@@ -664,7 +661,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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
|
||||
@@ -742,7 +739,7 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
subaddr_account,
|
||||
subaddr_indices,
|
||||
only_below ? only_below : MONEY_SUPPLY,
|
||||
0,
|
||||
1, // ignore_below
|
||||
top_block_index))
|
||||
continue;
|
||||
|
||||
@@ -812,85 +809,110 @@ bool get_address_openings_x_y(
|
||||
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);
|
||||
|
||||
// 2. perform ECDH derivations
|
||||
std::vector<crypto::key_derivation> main_derivations;
|
||||
std::vector<crypto::key_derivation> additional_derivations;
|
||||
bool is_carrot = carrot::is_carrot_transaction_v1(tx);
|
||||
wallet::perform_ecdh_derivations(
|
||||
main_tx_ephemeral_pubkeys,
|
||||
additional_tx_ephemeral_pubkeys,
|
||||
is_carrot ? w.get_account().get_keys().k_view_incoming : w.get_account().get_keys().m_view_secret_key,
|
||||
w.get_account().get_keys().get_device(),
|
||||
is_carrot,
|
||||
main_derivations,
|
||||
additional_derivations
|
||||
);
|
||||
// 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);
|
||||
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()
|
||||
};
|
||||
// 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;
|
||||
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);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
);
|
||||
bool 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
|
||||
);
|
||||
CHECK_AND_ASSERT_THROW_MES(r, "Failed to obtain openings for onetime address");
|
||||
|
||||
return true;
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
@@ -981,7 +1003,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);
|
||||
@@ -1003,14 +1025,16 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
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,
|
||||
@@ -1054,7 +1078,9 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
tx_proposal.sources,
|
||||
tx_proposal.fee,
|
||||
tx_proposal.tx_type,
|
||||
tx_proposal.amount_burnt,
|
||||
change_masks,
|
||||
return_enote_out,
|
||||
encrypted_payment_id);
|
||||
|
||||
// aliases
|
||||
@@ -1094,7 +1120,7 @@ cryptonote::transaction finalize_all_proofs_from_transfer_details(
|
||||
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,
|
||||
src.real_out_tx_key,
|
||||
src.real_out_additional_tx_keys,
|
||||
@@ -1216,16 +1242,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);
|
||||
|
||||
@@ -1249,16 +1283,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);
|
||||
@@ -1288,7 +1319,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
|
||||
@@ -1348,11 +1379,9 @@ 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,
|
||||
|
||||
@@ -125,19 +125,13 @@ std::vector<carrot::CarrotTransactionProposalV1> make_carrot_transaction_proposa
|
||||
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,
|
||||
|
||||
+136
-86
@@ -98,6 +98,7 @@ using namespace epee;
|
||||
#include "carrot_impl/format_utils.h"
|
||||
#include "tx_builder.h"
|
||||
#include "scanning_tools.h"
|
||||
#include "carrot_core/scan.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -1583,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
|
||||
@@ -2615,7 +2621,7 @@ void wallet2::process_new_scanned_transaction(
|
||||
continue;
|
||||
|
||||
// update m_transfers view-incoming scan info, and default values
|
||||
transfer_details& td = tools::add_element(m_transfers);
|
||||
transfer_details& td = m_transfers.emplace_back();
|
||||
td.m_block_height = height;
|
||||
td.m_internal_output_index = local_output_index;
|
||||
td.m_global_output_index = o_indices.at(local_output_index);
|
||||
@@ -2647,8 +2653,8 @@ void wallet2::process_new_scanned_transaction(
|
||||
}
|
||||
}
|
||||
|
||||
// override the key image for PROTOCOL/RETURN tx outputs.
|
||||
if (td.m_td_origin_idx != std::numeric_limits<uint64_t>::max())
|
||||
// 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())
|
||||
{
|
||||
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];
|
||||
@@ -2664,20 +2670,22 @@ 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_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");
|
||||
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;
|
||||
}
|
||||
@@ -2696,6 +2704,37 @@ void wallet2::process_new_scanned_transaction(
|
||||
// update m_transfer_indices
|
||||
m_transfers_indices[enote_scan_info->asset_type].insert(m_transfers.size()-1);
|
||||
|
||||
// Check for STAKE / AUDIT TX payouts
|
||||
if (tx.type == cryptonote::transaction_type::PROTOCOL && td.m_td_origin_idx != std::numeric_limits<uint64_t>::max()) {
|
||||
|
||||
// Attempt to get the origin TX
|
||||
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];
|
||||
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");
|
||||
|
||||
// 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
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
// Check for STAKE / AUDIT TXs
|
||||
if (tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::STAKE) {
|
||||
|
||||
// Add a "locked coins" entry so users don't freak out when they STAKE/AUDITOA
|
||||
m_locked_coins.insert({onetime_address, {0, tx.amount_burnt, tx.source_asset_type}});
|
||||
}
|
||||
|
||||
// update multisig info
|
||||
if (m_multisig)
|
||||
{
|
||||
@@ -2840,22 +2879,9 @@ void wallet2::process_new_scanned_transaction(
|
||||
{
|
||||
// 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};
|
||||
m_account.insert_subaddresses({{onetime_address, subaddr_ext}});
|
||||
// save to m_subaddresses as well, so that we can populate account subaddress map
|
||||
// when we open the wallet first time.
|
||||
m_subaddresses_extended[onetime_address] = subaddr_ext;
|
||||
|
||||
for (const auto &entry: tx_amounts_individual_outs[i->first]) {
|
||||
// update m_salvium_txs
|
||||
m_salvium_txs.insert({onetime_address, m_transfers.size()-1});
|
||||
m_salvium_txs.insert({std::get<1>(entry), m_transfers.size()-1});
|
||||
}
|
||||
|
||||
// delete change output from amounts
|
||||
@@ -2994,6 +3020,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);
|
||||
}
|
||||
@@ -3010,7 +3037,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()));
|
||||
@@ -3100,8 +3131,7 @@ void wallet2::process_new_blockchain_entry(const cryptonote::block& b,
|
||||
|
||||
m_last_block_reward = cryptonote::get_outs_money_amount(b.miner_tx);
|
||||
LOG_PRINT_L2("Processed block: " << bl_id << ", height " << height << ", " << miner_tx_handle_time + txs_handle_time << "(" << miner_tx_handle_time << "/" << txs_handle_time <<")ms");
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
if (!(height % 128))
|
||||
LOG_PRINT_L2( "Skipped block by timestamp, height: " << height << ", block time " << b.timestamp << ", account time " << m_account.get_createtime());
|
||||
}
|
||||
@@ -3369,44 +3399,32 @@ 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()) {
|
||||
const parsed_block &par_blk = parsed_blocks.at(i);
|
||||
const std::uint64_t height = start_height + i;
|
||||
const bool skip_scan_for_this_block = should_skip_block(par_blk.block, height);
|
||||
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)
|
||||
tools::threadpool::waiter scan_blocks_waiter(tpool);
|
||||
for (size_t j = 0; j < 10; ++j)
|
||||
{
|
||||
if (!skip_scan_for_this_block)
|
||||
tx_scan_job(tx, tx_output_idx);
|
||||
tx_output_idx += tx.vout.size();
|
||||
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));
|
||||
tx_output_idx += par_blk.block.miner_tx.vout.size();
|
||||
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.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)
|
||||
tpool.submit(&scan_blocks_waiter, std::bind(tx_scan_job, std::cref(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)
|
||||
// {
|
||||
// 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));
|
||||
// tx_output_idx += par_blk.block.miner_tx.vout.size();
|
||||
// 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.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)
|
||||
// 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++;
|
||||
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
|
||||
@@ -3426,7 +3444,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;
|
||||
@@ -3454,6 +3472,23 @@ void wallet2::process_parsed_blocks(const uint64_t start_height, const std::vect
|
||||
tx_output_idx += n_block_outputs;
|
||||
++current_index;
|
||||
}
|
||||
|
||||
// save accumulated return subaddresses to m_subaddresses_extended, so that we can re-insert
|
||||
// them into account after we restart the wallet.
|
||||
m_subaddresses_extended.clear();
|
||||
for (const auto& subaddr: m_account.get_subaddress_map_ref()) {
|
||||
if (subaddr.second.derive_type == carrot::AddressDeriveType::PreCarrot &&
|
||||
subaddr.second.is_return_spend_key == true
|
||||
) {
|
||||
m_subaddresses_extended.insert({subaddr.first, subaddr.second});
|
||||
}
|
||||
}
|
||||
|
||||
// save accumulated return output info to wallet
|
||||
m_return_output_info.clear();
|
||||
for (const auto& output_info: m_account.get_return_output_map_ref()) {
|
||||
m_return_output_info.insert({output_info.first, output_info.second});
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::refresh(bool trusted_daemon)
|
||||
@@ -4017,7 +4052,7 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height,
|
||||
}
|
||||
|
||||
|
||||
bool wallet2::add_address_book_row(const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress)
|
||||
bool wallet2::add_address_book_row(const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress, bool is_carrot)
|
||||
{
|
||||
wallet2::address_book_row a;
|
||||
a.m_address = address;
|
||||
@@ -4025,6 +4060,7 @@ bool wallet2::add_address_book_row(const cryptonote::account_public_address &add
|
||||
a.m_payment_id = payment_id ? *payment_id : crypto::null_hash8;
|
||||
a.m_description = description;
|
||||
a.m_is_subaddress = is_subaddress;
|
||||
a.m_is_carrot = is_carrot;
|
||||
|
||||
auto old_size = m_address_book.size();
|
||||
m_address_book.push_back(a);
|
||||
@@ -4033,7 +4069,7 @@ bool wallet2::add_address_book_row(const cryptonote::account_public_address &add
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wallet2::set_address_book_row(size_t row_id, const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress)
|
||||
bool wallet2::set_address_book_row(size_t row_id, const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress, bool is_carrot)
|
||||
{
|
||||
wallet2::address_book_row a;
|
||||
a.m_address = address;
|
||||
@@ -4041,6 +4077,7 @@ bool wallet2::set_address_book_row(size_t row_id, const cryptonote::account_publ
|
||||
a.m_payment_id = payment_id ? *payment_id : crypto::null_hash8;
|
||||
a.m_description = description;
|
||||
a.m_is_subaddress = is_subaddress;
|
||||
a.m_is_carrot = is_carrot;
|
||||
|
||||
const auto size = m_address_book.size();
|
||||
if (row_id >= size)
|
||||
@@ -6582,17 +6619,21 @@ 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);
|
||||
|
||||
// populate account subaddress list
|
||||
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
|
||||
// we assume none of these subaddresses are return tx subaddresses
|
||||
{{subaddress.first, {{subaddress.second.major, subaddress.second.minor}, carrot::AddressDeriveType::PreCarrot, false}}}
|
||||
);
|
||||
}
|
||||
m_account.insert_subaddresses(m_subaddresses_extended);
|
||||
|
||||
// populate account return output info
|
||||
m_account.insert_return_output_info(m_return_output_info);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -6799,9 +6840,8 @@ void wallet2::process_background_cache_on_open()
|
||||
background_w2->m_custom_background_key = m_custom_background_key;
|
||||
|
||||
// TODO: uncommet this block
|
||||
// carrot::carrot_and_legacy_account account = m_account;
|
||||
// account.forget_spend_key();
|
||||
// background_w2->m_account = account;
|
||||
background_w2->m_account.set_keys(m_account.get_keys(), false);
|
||||
background_w2->m_account.forget_spend_key();
|
||||
|
||||
// Load background cache from file
|
||||
background_w2->clear();
|
||||
@@ -7413,6 +7453,14 @@ bool wallet2::is_transfer_unlocked(const transfer_details& td)
|
||||
uint64_t unlock_time = 0;
|
||||
if (!cryptonote::get_output_unlock_time(td.m_tx.vout[td.m_internal_output_index], unlock_time))
|
||||
return false;
|
||||
if (unlock_time == 0) {
|
||||
if (td.m_tx.type == cryptonote::transaction_type::MINER || td.m_tx.type == cryptonote::transaction_type::PROTOCOL) {
|
||||
unlock_time = CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
|
||||
} else {
|
||||
unlock_time = CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE;
|
||||
}
|
||||
}
|
||||
|
||||
return is_transfer_unlocked(unlock_time, td.m_block_height);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
@@ -11562,9 +11610,8 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||
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..
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -11687,7 +11734,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
|
||||
@@ -11804,6 +11851,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
|
||||
|
||||
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
|
||||
|
||||
+27
-5
@@ -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,
|
||||
@@ -846,6 +859,7 @@ private:
|
||||
std::string m_description;
|
||||
bool m_is_subaddress;
|
||||
bool m_has_payment_id;
|
||||
bool m_is_carrot;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
VERSION_FIELD(0)
|
||||
@@ -854,6 +868,7 @@ private:
|
||||
FIELD(m_description)
|
||||
FIELD(m_is_subaddress)
|
||||
FIELD(m_has_payment_id)
|
||||
FIELD(m_is_carrot)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
@@ -1179,7 +1194,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);
|
||||
@@ -1403,6 +1419,7 @@ private:
|
||||
return;
|
||||
a & m_subaddresses.parent();
|
||||
a & m_subaddresses_extended.parent();
|
||||
a & m_return_output_info.parent();
|
||||
std::unordered_map<cryptonote::subaddress_index, crypto::public_key> dummy_subaddresses_inv;
|
||||
a & dummy_subaddresses_inv;
|
||||
a & m_subaddress_labels;
|
||||
@@ -1470,6 +1487,7 @@ private:
|
||||
FIELD(m_scanned_pool_txs[1])
|
||||
FIELD(m_subaddresses)
|
||||
FIELD(m_subaddresses_extended)
|
||||
FIELD(m_return_output_info)
|
||||
FIELD(m_subaddress_labels)
|
||||
FIELD(m_additional_tx_keys)
|
||||
FIELD(m_attributes)
|
||||
@@ -1630,8 +1648,8 @@ private:
|
||||
* \brief GUI Address book get/store
|
||||
*/
|
||||
std::vector<address_book_row> get_address_book() const { return m_address_book; }
|
||||
bool add_address_book_row(const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress);
|
||||
bool set_address_book_row(size_t row_id, const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress);
|
||||
bool add_address_book_row(const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress, bool is_carrot);
|
||||
bool set_address_book_row(size_t row_id, const cryptonote::account_public_address &address, const crypto::hash8 *payment_id, const std::string &description, bool is_subaddress, bool is_carrot);
|
||||
bool delete_address_book_row(std::size_t row_id);
|
||||
|
||||
uint64_t get_num_rct_outputs();
|
||||
@@ -2133,6 +2151,7 @@ private:
|
||||
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;
|
||||
serializable_unordered_map<crypto::public_key, carrot::return_output_info_t> m_return_output_info;
|
||||
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;
|
||||
@@ -2273,7 +2292,7 @@ BOOST_CLASS_VERSION(tools::wallet2::payment_details, 5)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::pool_payment_details, 1)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 8)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 18)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 19)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::reserve_proof_entry, 0)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 1)
|
||||
BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 1)
|
||||
@@ -2651,6 +2670,9 @@ namespace boost
|
||||
a & x.m_has_payment_id;
|
||||
if (x.m_has_payment_id)
|
||||
a & x.m_payment_id;
|
||||
if (ver < 19)
|
||||
return;
|
||||
a & x.m_is_carrot;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
}
|
||||
@@ -3286,9 +3313,9 @@ namespace tools
|
||||
const auto &entry = ab[idx];
|
||||
std::string address;
|
||||
if (entry.m_has_payment_id)
|
||||
address = cryptonote::get_account_integrated_address_as_str(m_wallet->nettype(), entry.m_address, entry.m_payment_id);
|
||||
address = cryptonote::get_account_integrated_address_as_str(m_wallet->nettype(), entry.m_address, entry.m_payment_id, entry.m_is_carrot);
|
||||
else
|
||||
address = get_account_address_as_str(m_wallet->nettype(), entry.m_is_subaddress, entry.m_address);
|
||||
address = get_account_address_as_str(m_wallet->nettype(), entry.m_is_subaddress, entry.m_address, entry.m_is_carrot);
|
||||
res.entries.push_back(wallet_rpc::COMMAND_RPC_GET_ADDRESS_BOOK_ENTRY::entry{idx, address, entry.m_description});
|
||||
}
|
||||
}
|
||||
@@ -3328,7 +3355,7 @@ namespace tools
|
||||
er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + req.address;
|
||||
return false;
|
||||
}
|
||||
if (!m_wallet->add_address_book_row(info.address, info.has_payment_id ? &info.payment_id : NULL, req.description, info.is_subaddress))
|
||||
if (!m_wallet->add_address_book_row(info.address, info.has_payment_id ? &info.payment_id : NULL, req.description, info.is_subaddress, info.is_carrot))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = "Failed to add address book entry";
|
||||
@@ -3387,12 +3414,13 @@ namespace tools
|
||||
entry.m_is_subaddress = info.is_subaddress;
|
||||
if (info.has_payment_id)
|
||||
entry.m_payment_id = info.payment_id;
|
||||
entry.m_is_carrot = info.is_carrot;
|
||||
}
|
||||
|
||||
if (req.set_description)
|
||||
entry.m_description = req.description;
|
||||
|
||||
if (!m_wallet->set_address_book_row(req.index, entry.m_address, req.set_address && entry.m_has_payment_id ? &entry.m_payment_id : NULL, entry.m_description, entry.m_is_subaddress))
|
||||
if (!m_wallet->set_address_book_row(req.index, entry.m_address, req.set_address && entry.m_has_payment_id ? &entry.m_payment_id : NULL, entry.m_description, entry.m_is_subaddress, entry.m_is_carrot))
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = "Failed to edit address book entry";
|
||||
|
||||
@@ -323,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);
|
||||
@@ -400,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);
|
||||
@@ -714,6 +720,7 @@ 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},
|
||||
@@ -722,6 +729,7 @@ 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,
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
change_index,
|
||||
|
||||
@@ -417,7 +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);
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
#include "carrot_impl/tx_proposal_utils.h"
|
||||
#include "carrot_impl/input_selection.h"
|
||||
#include "carrot_mock_helpers.h"
|
||||
#include "common/container_helpers.h"
|
||||
#include "crypto/generators.h"
|
||||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_basic/subaddress_index.h"
|
||||
@@ -63,7 +62,7 @@ static void unittest_scan_enote_set_multi_account(const std::vector<CarrotEnoteV
|
||||
res.reserve(accounts.size());
|
||||
|
||||
for (const auto *account : accounts)
|
||||
mock_scan_enote_set(enotes, encrypted_payment_id, *account, tools::add_element(res));
|
||||
mock_scan_enote_set(enotes, encrypted_payment_id, *account, res.emplace_back());
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
@@ -206,6 +205,7 @@ 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,
|
||||
@@ -214,6 +214,7 @@ 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,
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
change_index,
|
||||
@@ -355,7 +356,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_1)
|
||||
acc1.generate();
|
||||
|
||||
// 1 normal payment
|
||||
CarrotPaymentProposalV1 &normal_payment_proposal = tools::add_element( tx_proposal.per_account_payments[0].second).first;
|
||||
CarrotPaymentProposalV1 &normal_payment_proposal = tx_proposal.per_account_payments[0].second.emplace_back().first;
|
||||
normal_payment_proposal = CarrotPaymentProposalV1{
|
||||
.destination = acc0.cryptonote_address(),
|
||||
.amount = crypto::rand_idx((rct::xmr_amount) 1ull << 63),
|
||||
@@ -394,21 +395,21 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_2)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 1 subaddress payment
|
||||
tools::add_element(acc0.second).first = CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
// 1 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
// 1 integrated address payment
|
||||
tools::add_element(acc3.second).first = CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -443,7 +444,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_3)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 2 subaddress payment
|
||||
tools::add_element(acc0.second).first = CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -452,7 +453,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_3)
|
||||
acc0.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 2 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -461,7 +462,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_3)
|
||||
acc1.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 1 integrated address payment
|
||||
tools::add_element(acc3.second).first = CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -496,7 +497,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_4)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 2 subaddress payment
|
||||
tools::add_element(acc0.second).first = CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -505,7 +506,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_4)
|
||||
acc0.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 2 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -514,14 +515,14 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_4)
|
||||
acc1.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 1 integrated address payment
|
||||
tools::add_element(acc3.second).first = CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
// 1 main address selfsend
|
||||
tools::add_element(tx_proposal.explicit_selfsend_proposals).first.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
tx_proposal.explicit_selfsend_proposals.emplace_back().first.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = acc2.first.carrot_account_spend_pubkey,
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.enote_type = CarrotEnoteType::PAYMENT,
|
||||
@@ -529,7 +530,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_4)
|
||||
};
|
||||
|
||||
// 1 subaddress selfsend
|
||||
tools::add_element(tx_proposal.explicit_selfsend_proposals).first = CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
tx_proposal.explicit_selfsend_proposals.emplace_back().first = CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = acc2.first.subaddress({{4, 19}}).address_spend_pubkey,
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
@@ -560,7 +561,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_5)
|
||||
acc1.generate(AddressDeriveType::PreCarrot);
|
||||
|
||||
// 1 normal payment
|
||||
CarrotPaymentProposalV1 &normal_payment_proposal = tools::add_element( tx_proposal.per_account_payments[0].second).first;
|
||||
CarrotPaymentProposalV1 &normal_payment_proposal = tx_proposal.per_account_payments[0].second.emplace_back().first;
|
||||
normal_payment_proposal = CarrotPaymentProposalV1{
|
||||
.destination = acc0.cryptonote_address(),
|
||||
.amount = crypto::rand_idx((rct::xmr_amount) 1ull << 63),
|
||||
@@ -599,21 +600,21 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_6)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 1 subaddress payment
|
||||
tools::add_element(acc0.second).first = CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
// 1 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
// 1 integrated address payment
|
||||
tools::add_element(acc3.second).first = CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -648,7 +649,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_7)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 2 subaddress payment
|
||||
tools::add_element(acc0.second).first = CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -657,7 +658,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_7)
|
||||
acc0.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 2 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -666,7 +667,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_7)
|
||||
acc1.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 1 integrated address payment
|
||||
tools::add_element(acc3.second).first = CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -701,7 +702,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_8)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 2 subaddress payment
|
||||
tools::add_element(acc0.second).first = CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -710,7 +711,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_8)
|
||||
acc0.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 2 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -719,14 +720,14 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_8)
|
||||
acc1.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 1 integrated address payment
|
||||
tools::add_element(acc3.second).first = CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
// 1 main address selfsend
|
||||
tools::add_element(tx_proposal.explicit_selfsend_proposals).first.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
tx_proposal.explicit_selfsend_proposals.emplace_back().first.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = acc2.first.carrot_account_spend_pubkey,
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.enote_type = CarrotEnoteType::PAYMENT,
|
||||
@@ -734,7 +735,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_8)
|
||||
};
|
||||
|
||||
// 1 subaddress selfsend
|
||||
tools::add_element(tx_proposal.explicit_selfsend_proposals).first = CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
tx_proposal.explicit_selfsend_proposals.emplace_back().first = CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = acc2.first.subaddress({{4, 19}}).address_spend_pubkey,
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
@@ -766,7 +767,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_9)
|
||||
acc1.generate();
|
||||
|
||||
// 1 normal payment (subtractable)
|
||||
CarrotPaymentProposalV1 &normal_payment_proposal = tools::add_element( tx_proposal.per_account_payments[0].second).first;
|
||||
CarrotPaymentProposalV1 &normal_payment_proposal = tx_proposal.per_account_payments[0].second.emplace_back().first;
|
||||
normal_payment_proposal = CarrotPaymentProposalV1{
|
||||
.destination = acc0.cryptonote_address(),
|
||||
.amount = crypto::rand_idx((rct::xmr_amount) 1ull << 63),
|
||||
@@ -807,21 +808,21 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_10)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 1 subaddress payment (subtractable)
|
||||
tools::add_element(acc0.second) = {CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{ = {CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
}, true};
|
||||
|
||||
// 1 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
// 1 integrated address payment
|
||||
tools::add_element(acc3.second) = {CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -857,7 +858,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_11)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 2 subaddress payment
|
||||
tools::add_element(acc0.second).first = CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -867,7 +868,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_11)
|
||||
acc0.second.back().second = true; //set copy as subtractable
|
||||
|
||||
// 2 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -877,7 +878,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_11)
|
||||
acc1.second.back().second = true; //set copy as subtractable
|
||||
|
||||
// 1 integrated address payment
|
||||
tools::add_element(acc3.second).first = CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -913,7 +914,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_12)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 2 subaddress payment (1 subtractable)
|
||||
tools::add_element(acc0.second) = {CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{ = {CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -923,7 +924,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_12)
|
||||
acc0.second.back().second = false; //set not subtractable, first already is
|
||||
|
||||
// 2 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -932,14 +933,14 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_12)
|
||||
acc1.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 1 integrated address payment (subtractable)
|
||||
tools::add_element(acc3.second) = {CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
}, true};
|
||||
|
||||
// 1 main address selfsend
|
||||
tools::add_element(tx_proposal.explicit_selfsend_proposals).first.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
tx_proposal.explicit_selfsend_proposals.emplace_back().first.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = acc2.first.carrot_account_spend_pubkey,
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.enote_type = CarrotEnoteType::PAYMENT,
|
||||
@@ -947,7 +948,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_12)
|
||||
};
|
||||
|
||||
// 1 subaddress selfsend (subtractable)
|
||||
tools::add_element(tx_proposal.explicit_selfsend_proposals) = {CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
tx_proposal.explicit_selfsend_proposals.emplace_back().first = CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = acc2.first.subaddress({{4, 19}}).address_spend_pubkey,
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
@@ -979,7 +980,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_13)
|
||||
acc1.generate(AddressDeriveType::PreCarrot);
|
||||
|
||||
// 1 normal payment (subtractable)
|
||||
CarrotPaymentProposalV1 &normal_payment_proposal = tools::add_element( tx_proposal.per_account_payments[0].second).first;
|
||||
CarrotPaymentProposalV1 &normal_payment_proposal = tx_proposal.per_account_payments[0].second.emplace_back().first;
|
||||
normal_payment_proposal = CarrotPaymentProposalV1{
|
||||
.destination = acc0.cryptonote_address(),
|
||||
.amount = crypto::rand_idx((rct::xmr_amount) 1ull << 63),
|
||||
@@ -1020,21 +1021,21 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_14)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 1 subaddress payment (subtractable)
|
||||
tools::add_element(acc0.second) = {CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{ = {CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
}, true};
|
||||
|
||||
// 1 main address payment
|
||||
tools::add_element(acc1.second).first = CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
};
|
||||
|
||||
// 1 integrated address payment (subtractable)
|
||||
tools::add_element(acc3.second) = {CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -1070,7 +1071,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_15)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 2 subaddress payment (subtractable)
|
||||
tools::add_element(acc0.second) = {CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{ = {CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -1079,7 +1080,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_15)
|
||||
acc0.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 2 main address payment (subtractable)
|
||||
tools::add_element(acc1.second) = {CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -1088,7 +1089,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_15)
|
||||
acc1.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 1 integrated address payment (subtractable)
|
||||
tools::add_element(acc3.second) = {CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -1124,7 +1125,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_16)
|
||||
tx_proposal.self_sender_index = 2;
|
||||
|
||||
// 2 subaddress payment (subtractable)
|
||||
tools::add_element(acc0.second) = {CarrotPaymentProposalV1{
|
||||
acc0.second.emplace_back().first = CarrotPaymentProposalV1{ = {CarrotPaymentProposalV1{
|
||||
.destination = acc0.first.subaddress({{2, 3}}),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -1133,7 +1134,7 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_16)
|
||||
acc0.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 2 main address payment (subtractable)
|
||||
tools::add_element(acc1.second) = {CarrotPaymentProposalV1{
|
||||
acc1.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc1.first.cryptonote_address(),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
@@ -1142,22 +1143,22 @@ TEST(carrot_impl, multi_account_transfer_over_transaction_16)
|
||||
acc1.second.back().first.randomness = gen_janus_anchor(); //mangle anchor_norm
|
||||
|
||||
// 1 integrated address payment (subtractable)
|
||||
tools::add_element(acc3.second) = {CarrotPaymentProposalV1{
|
||||
acc3.second.emplace_back().first = CarrotPaymentProposalV1{
|
||||
.destination = acc3.first.cryptonote_address(gen_payment_id()),
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.randomness = gen_janus_anchor()
|
||||
}, true};
|
||||
|
||||
// 1 main address selfsend (subtractable)
|
||||
tools::add_element(tx_proposal.explicit_selfsend_proposals) = {{CarrotPaymentProposalSelfSendV1{
|
||||
tx_proposal.explicit_selfsend_proposals.emplace_back() = {CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = acc2.first.carrot_account_spend_pubkey,
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
.enote_type = CarrotEnoteType::PAYMENT,
|
||||
// no internal messages for legacy self-sends
|
||||
}}, true};
|
||||
}, true};
|
||||
|
||||
// 1 subaddress selfsend (subtractable)
|
||||
tools::add_element(tx_proposal.explicit_selfsend_proposals) = {CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
tx_proposal.explicit_selfsend_proposals.emplace_back() = {CarrotPaymentProposalVerifiableSelfSendV1{
|
||||
.proposal = CarrotPaymentProposalSelfSendV1{
|
||||
.destination_address_spend_pubkey = acc2.first.subaddress({{4, 19}}).address_spend_pubkey,
|
||||
.amount = crypto::rand_idx<rct::xmr_amount>(1000000),
|
||||
|
||||
@@ -188,6 +188,7 @@ 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},
|
||||
@@ -196,6 +197,7 @@ 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,
|
||||
cryptonote::transaction_type::TRANSFER,
|
||||
change_index,
|
||||
|
||||
@@ -226,7 +226,7 @@ std::tuple<std::vector<RCTOutputEnoteProposal>, crypto::public_key> make_return_
|
||||
get_output_proposal_return_v1(
|
||||
proposal_return,
|
||||
tx_return_first_key_image,
|
||||
&bob.s_view_balance_dev,
|
||||
nullptr, // s_view_balance_dev
|
||||
enote_proposal_return,
|
||||
encrypted_payment_id_return
|
||||
);
|
||||
|
||||
@@ -157,7 +157,7 @@ TEST(x25519, scmul_key_convergence)
|
||||
for (unsigned char j = 0; j < 8; ++j)
|
||||
{
|
||||
// add 2^i + j (sometimes with duplicates, which is okay)
|
||||
mx25519_privkey &s = tools::add_element(scalars);
|
||||
mx25519_privkey &s = scalars.emplace_back();
|
||||
memset(s.data, 0, sizeof(mx25519_privkey));
|
||||
const int msb_byte_index = i >> 3;
|
||||
const int msb_bit_index = i & 7;
|
||||
@@ -169,7 +169,7 @@ TEST(x25519, scmul_key_convergence)
|
||||
scalars.push_back(hex2pod<mx25519_privkey>("ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"));
|
||||
// add random
|
||||
const rct::key a = rct::skGen();
|
||||
memcpy(tools::add_element(scalars).data, &a, sizeof(mx25519_privkey));
|
||||
memcpy(scalars.emplace_back().data, &a, sizeof(mx25519_privkey));
|
||||
|
||||
std::vector<std::pair<rct::key, mx25519_pubkey>> points;
|
||||
// add base point
|
||||
|
||||
Reference in New Issue
Block a user