Compare commits

...

50 Commits

Author SHA1 Message Date
Some Random Crypto Guy 91814ebfd9 updated testnet seed nodes; bumped RC version 2025-08-21 13:31:03 +01:00
Some Random Crypto Guy 7b3e8007c8 bumped TESTNET DB version to prevent conflicts 2025-08-20 15:50:45 +01:00
Some Random Crypto Guy 141761957d bumped version to RC1 2025-08-20 15:48:05 +01:00
akildemir b2ab2f606c Security fixes (#48)
* unify tx versions; add missing protocol tx checks

* fixed errors with protocol_tx handling pre-Carrot

* fixed error caused by setting coinbase_tx version to 4

* fix eph pubkey check for protocol tx verification

* Update tx_pool.cpp

---------

Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
Co-authored-by: somerandomcryptoguy <139346562+somerandomcryptoguy@users.noreply.github.com>
2025-08-20 15:26:36 +01:00
Some Random Crypto Guy 40f0420e02 Merge branch 'carrot-integration' into develop 2025-08-19 12:07:40 +01:00
Some Random Crypto Guy 44e54ad555 fixed pre-Carrot sweep_all command; bumped RC version 2025-08-18 15:51:45 +01:00
Some Random Crypto Guy 69407ed8a5 bumped RC version 2025-08-18 12:08:24 +01:00
akildemir 13ee838f3c support for sweep_all (#47) 2025-08-18 12:06:56 +01:00
Some Random Crypto Guy ec33664734 fixed support for multiple STAKE TXs in same block, post-Carrot; bumped RC version 2025-08-14 17:42:47 +01:00
Some Random Crypto Guy bfe8c4606d fixed AUDIT payout scanning for split AUDIT TXs; bumped RC version 2025-08-14 12:07:53 +01:00
akildemir a159bed3ba remove tools::add_element 2025-08-08 14:54:55 +03:00
jeffro256 52f2065db4 carrot_core: update unclamped mx25519 for arm64 2025-08-08 14:28:54 +03:00
akildemir 0fd570a2c4 Merge pull request #46 from salvium/wallet-api-address-book-fix
fixed wallet API address book functionality to support Carrot addresses
2025-08-08 14:07:56 +03:00
Some Random Crypto Guy 7df7f2740d fixed wallet API address book functionality to support Carrot addresses 2025-08-08 11:14:55 +01:00
Some Random Crypto Guy 458af34c67 bumped version number to RC5 2025-08-06 19:31:59 +01:00
akildemir 21a3f5ca6f Merge pull request #44 from salvium/address-book-fixes 2025-08-06 20:52:36 +03:00
akildemir bc7a797b71 Merge pull request #43 from salvium/wallet-balance-stake-fix 2025-08-06 20:51:41 +03:00
Some Random Crypto Guy 9e888834e7 updated address book functionality to support Carrot addresses 2025-08-06 15:32:54 +01:00
Some Random Crypto Guy 9709fad4d6 fixed stake unlock time 2025-08-06 15:04:19 +01:00
akildemir 906e55f87b add return into type to wallet serialization (#42) 2025-08-06 15:00:56 +01:00
akildemir 92812621be Merge pull request #41 from salvium/background-sync-fix
background sync fix for Carrot accounts/keys
2025-08-06 13:35:38 +03:00
Some Random Crypto Guy 82b14a776f fixed background syncing issue with Carrot account keys 2025-08-06 11:27:23 +01:00
Some Random Crypto Guy 54a33225a2 fixed wallet balance during STAKE/AUDIT TX lifetime 2025-08-05 14:49:34 +01:00
akildemir d7584de579 Merge pull request #40 from salvium/fix-stake-tx-amount
merge STAKE/BURN TX fees fix
2025-08-05 16:28:28 +03:00
Some Random Crypto Guy a4c0d85bbb fixed stake/burn TX amount - stopped fees being deducted from amount_burnt 2025-08-05 14:07:26 +01:00
akildemir 609615779c Merge pull request #38 from salvium/tx-parallel-scanning-fix
Fixed wallet scanning parallelisation, speed up wallet scans from chain
2025-08-04 16:08:25 +03:00
Some Random Crypto Guy b9364b5749 fixed parallel scanning of blocks for wallet - max 10 blocks at a time, because of return_payment limitations 2025-08-04 14:02:05 +01:00
akildemir 7cd7bef3ca Merge pull request #37 from salvium/tx-size-calc-fix
Carrot TX size calculation fixes
2025-08-04 13:35:48 +03:00
Some Random Crypto Guy 80bd2d1ff0 fixed calculation for Carrot TX sizes - added Salvium-specific data 2025-08-04 11:01:33 +01:00
akildemir cbe84499fb use internal notes instead of special ones for change and return enotes (#36) 2025-08-01 13:54:59 +01:00
akildemir a8ee0a90e0 Merge pull request #34 from salvium/miner-fixes
fixed miner resumption issue
2025-08-01 14:24:14 +03:00
akildemir c9de861216 Merge pull request #35 from salvium/wallet-creation-address-fix
fixed incorrect wallet address displayed for Carrot when creating a new wallet
2025-08-01 14:22:22 +03:00
Some Random Crypto Guy 0239202f09 fixed incorrect wallet address displayed for Carrot when creating a new wallet 2025-07-31 11:48:43 +01:00
Some Random Crypto Guy 2dd6208a80 added mechanism to forcibly stop miner when crossing Carrot HF boundary, and allow mining to be restarted 2025-07-31 10:39:34 +01:00
akildemir 37594fe8fa Implement return tx functionality for post-carrot (#33)
* return tx fixes

* save change output for return tx

* successfully receive returned tx

* complete post-carrot return txs
2025-07-30 15:33:35 +01:00
akildemir e5c9b05ed6 Merge pull request #31 from salvium/ringct-fix
fixed RCT types to support ECDHINFO for Salvium One; fixed input and output limits for TXs
2025-07-24 14:44:06 +03:00
akildemir 9ba621b3ae post carrot stake tx support (#32)
* add support for stake txs and payouts post-carrot

* fixes on the stake return payments

* complete post-carrot stake txs

* rename protocol_tx_data to protocol_tx_data_t
2025-07-23 14:58:11 +01:00
Some Random Crypto Guy 9e20133ed9 fixed input and output limits for TXs 2025-07-23 10:35:14 +01:00
Some Random Crypto Guy 9c11200666 fixed RCT types to support ECDHINFO for Salvium One; fixed input and output limits for TXs 2025-07-23 10:21:13 +01:00
akildemir 3e0649a8d2 Merge pull request #29 from salvium/mining-migration-from-CN-to-Carrot
fixed migration of mining services from CN to Carrot
2025-07-23 12:07:20 +03:00
akildemir b87bfe002a Merge pull request #27 from salvium/carrot-addressing
fixed Carrot subaddress displaying in CLI wallet
2025-07-23 11:57:36 +03:00
Some Random Crypto Guy f2e69594a7 fixed migration of mining from CN to Carrot, including stopping miners from using wrong address pre- and post-Carrot HF 2025-07-22 11:51:21 +01:00
Some Random Crypto Guy 7b39504050 fixed carrot syncing of mainnet 2025-07-21 19:33:17 +01:00
Some Random Crypto Guy eff99e9287 fixed Carrot subaddress display in CLI wallet 2025-07-21 19:30:47 +01:00
somerandomcryptoguy 6f8fcdab03 fixed make depends for all major platforms (#26)
* fixed 'make depends' building

* fixed capture vars for MacOS

* fixed Linux build for make depends

---------

Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-07-19 12:25:45 +01:00
akildemir c7a739d885 Merge pull request #25 from salvium/premine-scan
fixed premine scanning using Carrot
2025-07-16 11:29:01 +03:00
Some Random Crypto Guy 608962068a fixed premine scan 2025-07-15 22:04:47 +01:00
Some Random Crypto Guy e7615b4c08 Merge branch 'carrot-integration' of https://github.com/salvium/salvium into carrot-integration 2025-07-15 16:05:31 +01:00
akildemir 28a9338ab7 Merge pull request #24 from salvium/audit-spend-fix
fixed subaddress_map issues allowing construction of TX for spending AUDIT and STAKE post-Carrot-HF
2025-07-15 13:48:51 +03:00
Some Random Crypto Guy 1d3747e9cd fixed subaddress_map issues allowing construction of TX for spending AUDIT and STAKE post-Carrot-HF 2025-07-15 10:50:03 +01:00
84 changed files with 1757 additions and 666 deletions
+5 -5
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
mingw32_CFLAGS=-pipe -pthread
mingw32_CFLAGS=-pipe
mingw32_CXXFLAGS=$(mingw32_CFLAGS)
mingw32_ARFLAGS=cr
+13 -15
View File
@@ -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
+4 -3
View File
@@ -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
+11 -5
View File
@@ -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 &&\
+2 -16
View File
@@ -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
+1
View File
@@ -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
+23 -27
View File
@@ -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 :=
+13 -9
View File
@@ -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)
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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
+13
View File
@@ -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
+113 -8
View File
@@ -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");
+7 -1
View File
@@ -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;
+1
View File
@@ -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; }
+1
View File
@@ -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;
}
}
}
+2
View File
@@ -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
+1 -1
View File
@@ -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";
+4
View File
@@ -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;
};
+7
View File
@@ -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,
+4
View File
@@ -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;
};
+16 -9
View File
@@ -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,
+35 -2
View File
@@ -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,
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
-1
View File
@@ -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
+34 -9
View File
@@ -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);
+4 -1
View File
@@ -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
+12 -18
View File
@@ -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(
+4
View File
@@ -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
+2
View File
@@ -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
+26 -4
View File
@@ -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
+11 -4
View File
@@ -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)
{
-7
View File
@@ -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)
+3
View File
@@ -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)
+37 -3
View File
@@ -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 {
+21 -3
View File
@@ -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);
+1
View File
@@ -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
View File
@@ -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"}}
};
}
+209 -40
View File
@@ -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__);
+7
View File
@@ -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
*
+3 -1
View File
@@ -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
+8 -24
View File
@@ -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
+10 -1
View File
@@ -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;
}
+30 -2
View File
@@ -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;
+3 -1
View File
@@ -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();
+3 -3
View File
@@ -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)
{
+3 -2
View File
@@ -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()
};
+23 -1
View File
@@ -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;
+3
View File
@@ -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");
+43 -4
View File
@@ -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();
+3
View File
@@ -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);
+43 -24
View File
@@ -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";
}
+4 -2
View File
@@ -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
View File
@@ -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"
+2 -2
View File
@@ -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
View File
@@ -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())
+9 -1
View File
@@ -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
View File
@@ -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,
+1 -7
View File
@@ -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
View File
@@ -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
View File
@@ -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>
+42 -14
View File
@@ -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";
+8
View File
@@ -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,
+3
View File
@@ -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);
+52 -51
View File
@@ -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),
+2
View File
@@ -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,
+1 -1
View File
@@ -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
);
+2 -2
View File
@@ -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