Compare commits

...

100 Commits

Author SHA1 Message Date
Codex Bot 42ec3826a0 Add store tx info and return addresses API
ci/gh-actions/depends / Cross-Mac aarch64 (push) Has been cancelled
ci/gh-actions/depends / ARM v8 (push) Has been cancelled
ci/gh-actions/depends / ARM v7 (push) Has been cancelled
ci/gh-actions/depends / i686 Linux (push) Has been cancelled
ci/gh-actions/depends / i686 Win (push) Has been cancelled
ci/gh-actions/depends / RISCV 64bit (push) Has been cancelled
ci/gh-actions/depends / Cross-Mac x86_64 (push) Has been cancelled
ci/gh-actions/depends / x86_64 Freebsd (push) Has been cancelled
ci/gh-actions/depends / x86_64 Linux (push) Has been cancelled
ci/gh-actions/depends / Win64 (push) Has been cancelled
2026-04-06 18:29:54 +02:00
Czarek Nakamoto c388ca652f add .patch-applied 2026-04-06 14:43:37 +02:00
Czarek Nakamoto c5edb53e57 serialize cache to JSON 2026-04-06 14:43:30 +02:00
julian e446baa47c ios no randomx JIT 2026-04-06 14:43:30 +02:00
Czarek Nakamoto 71d7754572 remove trivially_copyable assert 2026-04-06 14:43:30 +02:00
Czarek Nakamoto 691400c0cd change earliest fork height message 2026-04-06 14:43:29 +02:00
Czarek Nakamoto 2319090437 include locale only when targeting WIN32 2026-04-06 14:43:29 +02:00
Czarek Nakamoto d684c281c5 fix iOS depends build 2026-04-06 14:43:29 +02:00
cyan abc72ce9a1 add monero submodule support 2026-04-06 14:43:29 +02:00
Konstantin Ullrich 7ab8d9499c Add recoverDeterministicWalletFromSpendKey
This function is used by Cake Wallet to enable polyseed (dart implementation)
support.

Sourced from the following commit:
https://github.com/cake-tech/monero/commit/cb6fb5ab218878702ed151c0e3d5d68eb2732788

Co-authored-by: Godwin Asuquo <godilite@gmail.com>
2026-04-06 14:43:29 +02:00
M 25610c4c4b Add hex encoding and tx key getter for PendingTransction in wallet api. 2026-04-06 14:43:29 +02:00
tobtoht c1f36b676d coin control 2026-04-06 14:43:29 +02:00
tobtoht b9e87450eb polyseed
Co-authored-by: Czarek Nakamoto <cyjan@mrcyjanek.net>
2026-04-06 14:43:29 +02:00
Czarek Nakamoto c366058ba7 add dummy device for ledger 2026-04-06 14:43:29 +02:00
tobtoht ef8c2f00b9 UR functions
This commit adds UR functions for UR tasks,
I believe that the right place to get
UR strings is the wallet code itself,
especially because it allows us to
skip the part when we have to store
things to file to encode them later.
Now we are fully in memory

Things broken in the commit
- ledger support.
  AUTO_LOCK_CMD macro causes compile time
  issues with this patch. I don't know why
  just yet, this is a issue that I'll fix
  later. However (considering the purpose
  of this patch) it is not a dealbreaker.
2026-04-06 14:43:29 +02:00
Czarek Nakamoto 74811f7eb3 use proper error handling in get_seed 2026-04-06 14:43:29 +02:00
Czarek Nakamoto f699ca21c5 uint64_t missing definition fix 2026-04-06 14:43:29 +02:00
Czarek Nakamoto 20014ae7c2 store crash fix
Monero wallet crashes (sometimes) when it is syncing,
while the proper solution (that can be seen in feather)
is to not store wallet while it is being synced, this is not
acceptable for mobile wallets where OS can just come
and kill the wallet because it felt like it.

This patch depends on the background-sync patch, but
to use it as a standalone fix grabbing the definition for the
LOCK_REFRESH macro should be enough.

tobtoht suggested:
_say you want to store every 15 minutes during background sync. you stop the refresh every 15 minutes. then do something like this in the callback:_

```
// Make sure this doesn't run in the refresh thread
onRefreshed() {
  if (hasItBeen15MinutesSinceWeStored()) {
    store();
  }

  if (shouldWeContinueRefreshing()) {
    startRefresh();
  }
}
```

which works for crashes after the wallet is initially synced
but doesn't solve the issue for wallet that are syncing (it
would just wait for it to finish before actually storing).

Also imo store() functin should store the wallet, no matter
the current state.
2026-04-06 14:43:29 +02:00
Czarek Nakamoto 60713cc8e5 fix missing ___clear_cache when targetting iOS 2026-04-06 14:43:29 +02:00
Some Random Crypto Guy f60b7209f8 fixed wallet API regression on spend+view key access 2025-10-09 14:25:26 +01:00
Some Random Crypto Guy 3b00a41fff fixed broken carrotKeys() API method 2025-10-08 20:40:33 +01:00
somerandomcryptoguy 119a7fab57 added query_key wallet-RPC support for all Carrot keys (#69)
Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-10-08 20:29:10 +01:00
auruya 6d0a4a4d7b add carrotkeys fn to wallet api (#68) 2025-10-08 20:28:50 +01:00
Some Random Crypto Guy 45404ecc71 API fixes 2025-10-07 15:12:49 +01:00
Some Random Crypto Guy e5bfc2f6ad wallet API additions for better Carrot support 2025-10-07 13:32:15 +01:00
Some Random Crypto Guy c5be51053a added support for AUDIT, BURN, STAKE TXs to PendingTransaction wallet API 2025-10-07 12:34:58 +01:00
Some Random Crypto Guy d7a9facee9 improved UX for address command 2025-10-04 13:36:37 +01:00
Some Random Crypto Guy ce6f6e0593 Merge branch 'develop' of https://github.com/salvium/salvium into develop 2025-10-03 15:06:17 +01:00
somerandomcryptoguy f1efb700d2 improvements to wallet address formatting for RPC (#66)
* bumped version to v1.0.0

* added fast sync points up to 325,000

* added fast sync points up to 325,000 (part 2)

* RPC address formatting fixes

---------

Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-10-03 15:06:05 +01:00
auruya dd246296b9 Fix show qr code (#65)
* enable dual address type support in show_qr_code command

* delete comments
2025-10-03 15:05:49 +01:00
Some Random Crypto Guy 22334d7c6c Merge branch 'develop' of https://github.com/salvium/salvium into develop 2025-10-03 13:42:27 +01:00
somerandomcryptoguy c07698fcc8 improvements to wallet address formatting (#64)
* bumped version to v1.0.0

* added fast sync points up to 325,000

* added fast sync points up to 325,000 (part 2)

* initial import of CLI wallet improvements for address printing

* updated wallet address display in various places

---------

Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-10-03 13:10:28 +01:00
Some Random Crypto Guy ce69272638 Merge branch 'main' into develop 2025-10-02 14:41:30 +01:00
Some Random Crypto Guy 2b95d100b3 added fast sync points up to 325,000 (part 2) 2025-10-01 17:35:35 +01:00
Some Random Crypto Guy b7706d4def added fast sync points up to 325,000 2025-10-01 17:05:49 +01:00
Some Random Crypto Guy 845d46d7b3 bumped version to v1.0.0 2025-10-01 14:46:23 +01:00
Some Random Crypto Guy e4f8929f2c Merge branch 'develop' 2025-10-01 14:44:09 +01:00
Some Random Crypto Guy c03402d525 updated API methods for 3rd-party wallets 2025-10-01 14:40:47 +01:00
Some Random Crypto Guy d8b18b17f6 bumped RC version 2025-09-30 22:02:11 +01:00
Some Random Crypto Guy 5347266ed9 fixed a couple of wallet cache issues; fixed rescan_bc bug 2025-09-30 22:01:35 +01:00
somerandomcryptoguy 419c26adbf added tx_type setting for payment details - needed for wallet API (#61)
Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-09-12 16:34:02 +01:00
auruya 7727bdb51e Add stake tests (#60)
* update unit tests

* add stake transaction functional test
2025-09-12 09:39:02 +01:00
Some Random Crypto Guy 37a58646fd bumped RC version 2025-09-10 09:20:17 +01:00
somerandomcryptoguy 0e747e3f15 remove 2nd fork - STAKE issues resolved cleanly (#58)
* removed HF11

* fixed problem with AUDIT generation; fixed issue with empty PROTOCOL TX after HF10

* fixed protocol_tx version if empty at HF10 commencement; added validation of correct address type for destinations on TRANSFER

* fix is_carrot for stake txs

---------

Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
Co-authored-by: auruya <dream.glorix@gmail.com>
2025-09-10 09:16:14 +01:00
auruya caf8a0a962 fix-prevalidate-protocol-tx-for-carrot (#57) 2025-09-04 20:43:16 +01:00
Some Random Crypto Guy 1b60c08dce fixed issues with STAKE over HF10-HF11 thresholds; bumped RC version 2025-09-04 16:04:29 +01:00
Some Random Crypto Guy 1667514896 bumped RC version 2025-09-03 16:01:50 +01:00
auruya 041cd03098 Add hardfork for stake carrot integration (#55)
* Add hardfork for stake carrot integration

* Add hardfork for stake carrot integration

* fixed assertion failure

* Add hardfork for stake carrot integration

* Add hardfork for stake carrot integration

---------

Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-09-03 16:00:34 +01:00
somerandomcryptoguy 0c4998b091 added --generate-from-svb-key functionality (#53)
Co-authored-by: Some Random Crypto Guy <somerandomcryptoguy@protonmail.com>
2025-09-03 12:33:09 +01:00
auruya 7f25459169 add dest_asset_type check (#52) 2025-09-01 14:18:11 +01:00
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
145 changed files with 6002 additions and 1023 deletions
+12 -1
View File
@@ -6,11 +6,22 @@
url = https://github.com/trezor/trezor-common.git
[submodule "external/randomx"]
path = external/randomx
url = https://github.com/tevador/RandomX
url = https://github.com/MrCyjaneK/RandomX
branch = cyjan-fix-ios
[submodule "external/utf8proc"]
path = external/utf8proc
url = https://github.com/JuliaStrings/utf8proc.git
[submodule "external/polyseed"]
path = external/polyseed
url = https://github.com/tevador/polyseed.git
[submodule "external/supercop"]
path = external/supercop
url = https://github.com/monero-project/supercop
branch = monero
[submodule "external/bc-ur"]
path = external/bc-ur
url = https://github.com/MrCyjaneK/bc-ur
branch = misc
[submodule "external/miniupnp"]
path = external/miniupnp
url = https://github.com/miniupnp/miniupnp
View File
+20 -15
View File
@@ -45,10 +45,6 @@ if (POLICY CMP0148)
endif()
include(FindPythonInterp)
if (IOS)
INCLUDE(CmakeLists_IOS.txt)
endif()
project(salvium)
option (USE_CCACHE "Use ccache if a usable instance is found" ON)
@@ -100,6 +96,7 @@ set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 17)
add_definitions(-D_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES) # boost: no template named 'unary_function' in namespace 'std'; did you mean '__unary_function'?
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
@@ -225,9 +222,9 @@ function(forbid_undefined_symbols)
cmake_minimum_required(VERSION 3.5)
project(test)
option(EXPECT_SUCCESS "" ON)
file(WRITE "${CMAKE_SOURCE_DIR}/incorrect_source.cpp" "void undefined_symbol(); void symbol() { undefined_symbol(); }")
file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/incorrect_source.cpp" "void undefined_symbol(); void symbol() { undefined_symbol(); }")
if (EXPECT_SUCCESS)
file(APPEND "${CMAKE_SOURCE_DIR}/incorrect_source.cpp" " void undefined_symbol() {}; ")
file(APPEND "${CMAKE_CURRENT_SOURCE_DIR}/incorrect_source.cpp" " void undefined_symbol() {}; ")
endif()
add_library(l0 SHARED incorrect_source.cpp)
add_library(l1 MODULE incorrect_source.cpp)
@@ -367,12 +364,15 @@ if(NOT MANUAL_SUBMODULES)
endfunction ()
message(STATUS "Checking submodules")
# check_submodule(external/bc-ur)
check_submodule(external/miniupnp)
check_submodule(external/rapidjson)
check_submodule(external/trezor-common)
check_submodule(external/randomx)
check_submodule(external/supercop)
check_submodule(external/mx25519)
check_submodule(external/polyseed)
check_submodule(external/utf8proc)
endif()
endif()
@@ -390,7 +390,7 @@ else()
endif()
list(INSERT CMAKE_MODULE_PATH 0
"${CMAKE_SOURCE_DIR}/cmake")
"${CMAKE_CURRENT_SOURCE_DIR}/cmake")
if (NOT DEFINED ENV{DEVELOPER_LOCAL_TOOLS})
message(STATUS "Could not find DEVELOPER_LOCAL_TOOLS in env (not required)")
@@ -459,7 +459,7 @@ elseif(CMAKE_SYSTEM_NAME MATCHES ".*BSDI.*")
set(BSDI TRUE)
endif()
include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include external/mx25519/include)
include_directories(external/rapidjson/include external/easylogging++ src contrib/epee/include external external/supercop/include external/mx25519/include external/polyseed/include external/utf8proc)
if(APPLE)
cmake_policy(SET CMP0042 NEW)
@@ -692,16 +692,21 @@ include_directories(${LMDB_INCLUDE})
include_directories(${LIBUNWIND_INCLUDE})
link_directories(${LIBUNWIND_LIBRARY_DIRS})
# Final setup for hid
if (HIDAPI_FOUND)
message(STATUS "Using HIDAPI include dir at ${HIDAPI_INCLUDE_DIR}")
add_definitions(-DHAVE_HIDAPI)
include_directories(${HIDAPI_INCLUDE_DIR})
link_directories(${LIBHIDAPI_LIBRARY_DIRS})
if (HIDAPI_DUMMY)
add_definitions(-DHIDAPI_DUMMY)
else()
message(STATUS "Could not find HIDAPI")
# Final setup for hid
if (HIDAPI_FOUND)
message(STATUS "Using HIDAPI include dir at ${HIDAPI_INCLUDE_DIR}")
add_definitions(-DHAVE_HIDAPI)
include_directories(${HIDAPI_INCLUDE_DIR})
link_directories(${LIBHIDAPI_LIBRARY_DIRS})
else()
message(STATUS "Could not find HIDAPI")
endif()
endif()
# Trezor support check
include(CheckTrezor)
+35
View File
@@ -0,0 +1,35 @@
# Use Ubuntu 24.04 as base
FROM ubuntu:24.04 AS builder
ENV DEBIAN_FRONTEND=noninteractive
# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential cmake pkg-config git imagemagick libcap-dev librsvg2-bin libz-dev \
g++-mingw-w64-x86-64 clang gcc-arm-none-eabi binutils-x86-64-linux-gnu libtiff-tools \
libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev \
libreadline-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev \
libprotobuf-dev protobuf-compiler libudev-dev libboost-all-dev python3 ccache doxygen graphviz \
ca-certificates curl zip libtool gperf \
&& rm -rf /var/lib/apt/lists/*
# Clone the develop branch
WORKDIR /opt
RUN git clone --recursive -b develop https://github.com/salvium/salvium.git
WORKDIR /opt/salvium
# make the script runnable
RUN chmod +x make_releases.sh
# Make sure the output folder exists
RUN mkdir ~/releases
# Expose the releases directory for copying zip files to the host
VOLUME ["~/releases"]
ENTRYPOINT ["/opt/salvium/make_releases.sh"]
# To access the generated zip files on your host, run the container with:
# docker run -v ~/releases:/root/releases <image>
# This will copy the zip files to your host's ~/salvium-releases directory.
+7 -7
View File
@@ -1,6 +1,6 @@
# Salvium Zero v0.9.9
# Salvium One v1.0.0
Copyright (c) 2023-2024, Salvium
Copyright (c) 2023-2025, Salvium
Portions Copyright (c) 2014-2023, The Monero Project
Portions Copyright (c) 2012-2013 The Cryptonote developers.
@@ -47,7 +47,7 @@ As with many development projects, the repository on GitHub is considered to be
## Supporting the project
Salvium is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Go to [https://salvium.io/donate/](https://salvium.io/donate/) for more information.
Salvium is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Go to [https://salvium.io/donate](https://salvium.io/donate) for more information.
## License
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
```bash
cd salvium
git checkout v0.9.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
@@ -6,7 +6,7 @@ macro(CHECK_LINKER_FLAG flag VARIABLE)
message(STATUS "Looking for ${flag} linker flag")
endif()
set(_cle_source ${CMAKE_SOURCE_DIR}/cmake/CheckLinkerFlag.c)
set(_cle_source ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckLinkerFlag.c)
set(saved_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
set(CMAKE_C_FLAGS "${flag}")
+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
@@ -28,7 +28,7 @@
#pragma once
#include "memwipe.h"
#include <stdint.h>
#include <boost/utility/string_ref.hpp>
#include <string>
-1
View File
@@ -162,7 +162,6 @@ namespace epee
{
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
static_assert(alignof(T) == 1, "type may have padding");
return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)};
}
+7
View File
@@ -34,6 +34,7 @@
#include <string>
#include "memwipe.h"
#include "fnv1.h"
#include "serialization/keyvalue_serialization.h"
namespace epee
{
@@ -75,6 +76,12 @@ namespace epee
bool operator!=(const wipeable_string &other) const noexcept { return buffer != other.buffer; }
wipeable_string &operator=(wipeable_string &&other);
wipeable_string &operator=(const wipeable_string &other);
char& operator[](size_t idx);
const char& operator[](size_t idx) const;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(buffer)
END_KV_SERIALIZE_MAP()
private:
void grow(size_t sz, size_t reserved = 0);
+10
View File
@@ -261,4 +261,14 @@ wipeable_string &wipeable_string::operator=(const wipeable_string &other)
return *this;
}
char& wipeable_string::operator[](size_t idx) {
CHECK_AND_ASSERT_THROW_MES(idx < buffer.size(), "Index out of bounds");
return buffer[idx];
}
const char& wipeable_string::operator[](size_t idx) const {
CHECK_AND_ASSERT_THROW_MES(idx < buffer.size(), "Index out of bounds");
return buffer[idx];
}
}
+3
View File
@@ -69,5 +69,8 @@ endif()
add_subdirectory(db_drivers)
add_subdirectory(easylogging++)
add_subdirectory(qrcodegen)
add_subdirectory(polyseed EXCLUDE_FROM_ALL)
add_subdirectory(utf8proc EXCLUDE_FROM_ALL)
add_subdirectory(bc-ur)
add_subdirectory(randomx EXCLUDE_FROM_ALL)
add_subdirectory(mx25519)
Vendored Submodule
+1
Submodule external/bc-ur added at d82e7c753e
Vendored Submodule
+1
Submodule external/polyseed added at bd79f5014c
Vendored Submodule
+1
Submodule external/utf8proc added at 3de4596fbe
+1
View File
@@ -98,6 +98,7 @@ add_subdirectory(net)
add_subdirectory(hardforks)
add_subdirectory(blockchain_db)
add_subdirectory(mnemonics)
add_subdirectory(polyseed)
add_subdirectory(rpc)
add_subdirectory(seraphis_crypto)
if(NOT IOS)
+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; }
Binary file not shown.
+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,55 @@ 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::create_from_svb_key(const cryptonote::account_public_address& address, const crypto::secret_key& svb_key)
{
// top level keys
m_keys.s_master = crypto::null_skey;
make_carrot_provespend_key(m_keys.s_master, m_keys.k_prove_spend);
m_keys.s_view_balance = svb_key;
// view balance keys
make_carrot_viewincoming_key(m_keys.s_view_balance, m_keys.k_view_incoming);
make_carrot_generateimage_key(m_keys.s_view_balance, m_keys.k_generate_image);
make_carrot_generateaddress_secret(m_keys.s_view_balance, m_keys.s_generate_address);
// carrot account address - use the provided address spend pubkey
m_keys.m_carrot_account_address = address;
k_view_incoming_dev.view_key_scalar_mult_ed25519(m_keys.m_carrot_account_address.m_spend_public_key,
m_keys.m_carrot_account_address.m_view_public_key
);
// carrot main wallet address
m_keys.m_carrot_main_address = address;
k_view_incoming_dev.view_key_scalar_mult_ed25519(crypto::get_G(),
m_keys.m_carrot_main_address.m_view_public_key
);
this->default_derive_type = AddressDeriveType::Carrot;
generate_subaddress_map();
}
//----------------------------------------------------------------------------------------------------------------------
void carrot_and_legacy_account::set_carrot_keys(const AddressDeriveType default_derive_type)
{
// top level keys
@@ -328,6 +382,7 @@ void carrot_and_legacy_account::set_carrot_keys(const AddressDeriveType default_
m_keys.m_carrot_account_address.m_spend_public_key,
m_keys.m_carrot_account_address.m_view_public_key
);
m_keys.m_carrot_account_address.m_is_carrot = true;
// carrot main wallet address
m_keys.m_carrot_main_address.m_spend_public_key = m_keys.m_carrot_account_address.m_spend_public_key;
@@ -335,6 +390,7 @@ void carrot_and_legacy_account::set_carrot_keys(const AddressDeriveType default_
crypto::get_G(),
m_keys.m_carrot_main_address.m_view_public_key
);
m_keys.m_carrot_main_address.m_is_carrot = true;
this->default_derive_type = default_derive_type;
generate_subaddress_map();
@@ -345,7 +401,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,
@@ -106,12 +153,50 @@ namespace carrot
const AddressDeriveType default_derive_type = AddressDeriveType::Carrot
);
void create_from_svb_key(const cryptonote::account_public_address& address, const crypto::secret_key& svb_key);
void set_carrot_keys(const AddressDeriveType default_derive_type = AddressDeriveType::Carrot);
void insert_subaddresses(const std::unordered_map<crypto::public_key, subaddress_index_extended>& subaddress_map);
void insert_return_output_info(
const std::unordered_map<crypto::public_key, return_output_info_t>& input_context_map
);
AddressDeriveType resolve_derive_type(const AddressDeriveType derive_type) const;
private:
std::unordered_map<crypto::public_key, subaddress_index_extended> subaddress_map;
// Kr -> return_output_info
std::unordered_map<crypto::public_key, return_output_info_t> return_output_map;
};
}
namespace boost
{
namespace serialization
{
template <class Archive>
inline typename std::enable_if<!Archive::is_loading::value, void>::type initialize_transfer_details(Archive &a, carrot::return_output_info_t &x, const boost::serialization::version_type ver)
{
}
template <class Archive>
inline typename std::enable_if<Archive::is_loading::value, void>::type initialize_transfer_details(Archive &a, carrot::return_output_info_t &x, const boost::serialization::version_type ver)
{
x.input_context = carrot::input_context_t();
x.K_o = crypto::public_key();
x.K_change = crypto::public_key();
x.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)
{
+5 -1
View File
@@ -28,7 +28,11 @@
if(APPLE)
if(DEPENDS)
list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework ApplicationServices -framework AppKit -framework IOKit")
if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS")
list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit")
else()
list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework ApplicationServices -framework AppKit -framework IOKit")
endif()
else()
find_library(IOKIT_LIBRARY IOKit)
mark_as_advanced(IOKIT_LIBRARY)
-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)
+6 -1
View File
@@ -28,7 +28,11 @@
if(APPLE)
if(DEPENDS)
list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework ApplicationServices -framework AppKit -framework IOKit")
if(${CMAKE_SYSTEM_NAME} STREQUAL "iOS")
list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit")
else()
list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework ApplicationServices -framework AppKit -framework IOKit")
endif()
else()
find_library(IOKIT_LIBRARY IOKit)
mark_as_advanced(IOKIT_LIBRARY)
@@ -71,6 +75,7 @@ target_link_libraries(cryptonote_basic
checkpoints
cryptonote_format_utils_basic
device
polyseed_wrapper
oracle
${Boost_DATE_TIME_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
+25 -1
View File
@@ -89,12 +89,16 @@ DISABLE_VS_WARNINGS(4244 4345)
void account_keys::xor_with_key_stream(const crypto::chacha_key &key)
{
// encrypt a large enough byte stream with chacha20
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (2 + m_multisig_keys.size()));
epee::wipeable_string key_stream = get_key_stream(key, m_encryption_iv, sizeof(crypto::secret_key) * (3 + m_multisig_keys.size()) + m_passphrase.size());
const char *ptr = key_stream.data();
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
m_spend_secret_key.data[i] ^= *ptr++;
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
m_view_secret_key.data[i] ^= *ptr++;
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
m_polyseed.data[i] ^= *ptr++;
for (size_t i = 0; i < m_passphrase.size(); ++i)
m_passphrase.data()[i] ^= *ptr++;
for (crypto::secret_key &k: m_multisig_keys)
{
for (size_t i = 0; i < sizeof(crypto::secret_key); ++i)
@@ -151,7 +155,11 @@ 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();
m_keys.m_polyseed = crypto::secret_key();
m_keys.m_passphrase.wipe();
}
//-----------------------------------------------------------------
void account_base::set_spend_key(const crypto::secret_key& spend_secret_key)
@@ -163,6 +171,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)
@@ -257,6 +266,21 @@ DISABLE_VS_WARNINGS(4244 4345)
create_from_keys(address, fake, viewkey);
}
//-----------------------------------------------------------------
void account_base::create_from_polyseed(const polyseed::data& seed, const epee::wipeable_string &passphrase)
{
crypto::secret_key secret_key;
seed.keygen(&secret_key, sizeof(secret_key));
if (!passphrase.empty()) {
secret_key = cryptonote::decrypt_key(secret_key, passphrase);
}
generate(secret_key, true, false);
seed.save(m_keys.m_polyseed.data);
m_keys.m_passphrase = passphrase;
}
//-----------------------------------------------------------------
bool account_base::make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys)
{
m_keys.m_account_address.m_spend_public_key = spend_public_key;
+6
View File
@@ -33,6 +33,7 @@
#include "cryptonote_basic.h"
#include "crypto/crypto.h"
#include "serialization/keyvalue_serialization.h"
#include "polyseed/polyseed.hpp"
#include "carrot_core/account_secrets.h"
#include "carrot_core/address_utils.h"
@@ -52,6 +53,8 @@ namespace cryptonote
std::vector<crypto::secret_key> m_multisig_keys;
hw::device *m_device = &hw::get_device("default");
crypto::chacha_iv m_encryption_iv;
crypto::secret_key m_polyseed;
epee::wipeable_string m_passphrase; // Only used with polyseed
// carrot secret keys (minus k_v, which is shared with legacy k_v)
crypto::secret_key s_master;
@@ -75,6 +78,8 @@ namespace cryptonote
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(m_multisig_keys)
const crypto::chacha_iv default_iv{{0, 0, 0, 0, 0, 0, 0, 0}};
KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(m_encryption_iv, default_iv)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_polyseed)
KV_SERIALIZE(m_passphrase)
END_KV_SERIALIZE_MAP()
void encrypt(const crypto::chacha_key &key);
@@ -101,6 +106,7 @@ namespace cryptonote
void create_from_device(hw::device &hwdev);
void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey);
void create_from_polyseed(const polyseed::data &polyseed, const epee::wipeable_string &passphrase);
bool make_multisig(const crypto::secret_key &view_secret_key, const crypto::secret_key &spend_secret_key, const crypto::public_key &spend_public_key, const std::vector<crypto::secret_key> &multisig_keys);
const account_keys& get_keys() const;
std::string get_public_address_str(network_type nettype) const;
+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();
@@ -1381,17 +1381,26 @@ namespace cryptonote
for (const auto &o: tx.vout)
{
if (hf_version >= HF_VERSION_CARROT)
{
// from v11, require outputs be carrot outputs
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx));
} else {
if (hf_version >= HF_VERSION_CARROT) {
if (tx.type != cryptonote::transaction_type::PROTOCOL) {
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_carrot_v1 in transaction id=" << get_transaction_hash(tx));
} else {
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) ||
o.target.type() == typeid(txout_to_tagged_key) ||
o.target.type() == typeid(txout_to_carrot_v1), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key or txout_to_carrot_v1 in protocol transaction");
// require all outputs in a tx be of the same type
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
<< "expected matching variant types in protocol transaction");
}
}
else {
// require outputs be of type txout_to_key OR txout_to_tagged_key
// to allow grace period before requiring all to be txout_to_tagged_key
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction");
// require all outputs in a tx be of the same type
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
+25 -7
View File
@@ -46,7 +46,7 @@
#include "boost/logic/tribool.hpp"
#include <boost/filesystem.hpp>
#ifdef __APPLE__
#if defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
#include <sys/times.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/ps/IOPSKeys.h>
@@ -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);
@@ -884,7 +902,7 @@ namespace cryptonote
return true;
#elif defined(__APPLE__)
#elif defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
mach_msg_type_number_t count;
kern_return_t status;
@@ -950,7 +968,7 @@ namespace cryptonote
return true;
}
#elif (defined(__linux__) && defined(_SC_CLK_TCK)) || defined(__APPLE__) || defined(__FreeBSD__)
#elif (defined(__linux__) && defined(_SC_CLK_TCK)) || (defined(__APPLE__) && !defined(TARGET_OS_IPHONE)) || defined(__FreeBSD__)
struct tms tms;
if ( times(&tms) != (clock_t)-1 )
@@ -979,7 +997,7 @@ namespace cryptonote
return boost::logic::tribool(power_status.ACLineStatus != 1);
}
#elif defined(__APPLE__)
#elif defined(__APPLE__) && !defined(TARGET_OS_IPHONE)
#if TARGET_OS_MAC && (!defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7)
return boost::logic::tribool(IOPSGetTimeRemainingEstimate() != kIOPSTimeRemainingUnlimited);
+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;
+23 -36
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
@@ -87,8 +88,8 @@
#define PREMINE_AMOUNT_UPFRONT ((uint64_t)650000000000000ull) // 3.4% of MONEY_SUPPLY
#define PREMINE_AMOUNT_MONTHLY ((uint64_t)65000000000000ull) // 8.6%/24 of MONEY_SUPPLY
#define TREASURY_SAL1_MINT_AMOUNT ((uint64_t)65000000000000ull) // 650K
#define TREASURY_SAL1_MINT_COUNT 16 // 16 times
#define TREASURY_SAL1_MINT_AMOUNT ((uint64_t)130000000000000ull) // 1.3M
#define TREASURY_SAL1_MINT_COUNT 8 // 8 times
#define DIFFICULTY_TARGET_V2 120 // seconds
#define DIFFICULTY_TARGET_V1 60 // seconds - before first fork
@@ -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
@@ -273,6 +274,8 @@
#define DNS_BLOCKLIST_LIFETIME (86400 * 8)
#define POLYSEED_COIN POLYSEED_MONERO
#define PRICING_RECORD_VALID_BLOCKS 10
#define PRICING_RECORD_VALID_TIME_DIFF_FROM_BLOCK 120 // seconds
@@ -318,22 +321,14 @@ 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 = {
{1000000ULL, {"a1bdd1da651fbbb845232816e1aa2d4ff29b790f10bbd4f574a012f1199e15a4", "b0733ab6f251b16458efa9ebb3fb99bd54d43173b5768fe9ffc42e0fe46ae3a8", "00", "00"}},
{1020000ULL, {"47996eccbcc078b06d0f6ece37bf3a700c2bd60adfdd898b22096f16a9ad315c", "fd6bcceb4799ee067d59b97a6f66a0f9a70f134220259d3b4d6a2278ba4aca4c", "00", "00"}},
{1040000ULL, {"a3e6754a849b80c21a77e6065fefdae29eeeabf17c407453356244a00545bdb8", "3d395454df1452d715d27190e022b20395871c99af578f7251c3f9752e0274a6", "00", "00"}},
{1060000ULL, {"0d5e97a910e0f9c606ad9c711b6595aaed142d857cde2efa519112b9a29240d5", "56c29e28bdcf4f20b4b45906b93ae7c4bf9ee82e18cd45543cb69a14ce5efb88", "00", "00"}},
{1080000ULL, {"495fa363de88915aa8b74818c4b80715a882a688b4f7127ab7cd3b6885f3567a", "d42dfe0da5579c82e8255eba8c0a17170023f14a6a5030da6abf9f10abb52cbb", "00", "00"}},
{1100000ULL, {"85ea10ec40390e4f406446fb519e974d89536154045c6df28bb3b538b254e20d", "0ce2b7dd3a8ce8b596889dac8081a62f98fd70f1f043944ab4ac592c3c59e77b", "00", "00"}},
{1120000ULL, {"40f201b38a319dda81e7201e57fea7924067a4a332ed71b8e51ec29ac2d67310", "8289aa6963b98d1034e94eae55d8be6b33d0a88f14f174ebcbaec70837986c7c", "00", "00"}},
{1140000ULL, {"c5a648cc7846341357b7b4653a58f9eb4800d88b5de587bceec7a5c28f98d05a", "3f308a203845d88e5e728fcebcdcea1f90e2f424d461617993c672a6138ad2d8", "00", "00"}},
{1160000ULL, {"4c51d6550b8eeb6cc8f0d395cc83a5f90ec2a4d86501b3f68da48d618ccf5711", "53f0bd8cebeefb3a88fffa5d7f6ad43d4712608ded561732467ca499df940454", "00", "00"}},
{1180000ULL, {"ce2f5d82118fed03d5e269e285fc16189a6cd34f38999e5c055a5dea5fce61bc", "f7fc6948b194d9bd6f2df6ecb83f04e6c8d1a2556a63fedb310a4631fe1bfc42", "00", "00"}},
{1200000ULL, {"6248028fd77fb02b5c6ea72dea10b417891a2da7aaf9565aed382e063b4981a3", "63986e1177499bdb23cd49afb519ec18f38cb1b0c386220b376d8ffdc2e37890", "00", "00"}},
{1220000ULL, {"6adcb695aa5d6d01133c68900f29e501e9549816e827ea0c164bbc78f3534dd6", "6a440ccb18f5e703e8000de3865ac40d4c18f081270d32eef377dc831f28d8d0", "00", "00"}},
{1240000ULL, {"b97a4d2259480f34f20e41c489ab5c2e5ae9ee84d8672a7eff8012f2260e121e", "e6eb9147ff40e22209d321d0f1bfbfe20acf5ceb6b9d0bfb13688ad28aa1232e", "00", "00"}},
{1260000ULL, {"4fd214602a36902f22d16927244c456e8cc5a406a9570131f138a028214ffdf0", "34060b8bd96009b9b298280ebd84fa9587fa8c9df6fb5ad0270fb6cd2098885c", "00", "00"}},
{1280000ULL, {"9d60178ec6d6599d7a31298f2559fb9c3111f2c70494b3a1638db877ea55b808", "7985ed03856a929663e954738d0938713407717835f760c7ca4d54844a128c91", "00", "00"}},
{1300000ULL, {"cd65718eab234bf419332e53bd2f48e2ade70af48c5e126ab5080321e1493dfc", "581cb4cca7a0a029ee2cac51dfc00a0c3a657d2eaf67ed3c6ae7bacc11b4f007", "00", "00"}},
{334750, {"1b2cd3ff56aa77c0cbab0473bfb96697ebdd0b25ad230136bfe41d5dc1ef265f","718cf02eabca157fd7ad7f8537db217624bfe1ca99dd09e758357e7000a5e57a","789cca3def51fb879eb7fbca271869b7","79bd0c"}},
{356350, {"b51acbf35265d09f3cfb83dcabde2746991ddf0d30b5a4ecc34043b349a77031","9dc0d2e9534cdccf83494687c55c67c8c1b29834acf97cce53124a08a9549231","588ebc2918d06c009a18a28a8ab76694","ab8c23"}},
{377950, {"771c6865980493846cbb049b34f72b937878cf799ae1126775df35064cf53526","60d340613c7721aeb03f2de1b56e2916d6cb023cc668acaca00e1606e0bb7f64","198bb0e5880c8abf8108158284ca7637","9b93f2"}},
{399550, {"d9159f9bb654230382a69bb7a739c14f9d506c21dba5be9f4cdf66126ed1b24e","c3b34e7f9977f31f659abd9306b650416a674ed7bcfb8c75b257040a1a06b8b9","6f0de181716e0a9e100228d58f11d42c","4c87fd"}},
{421150, {"1e2ab1ae204e7a9375f5b57fed2524e2d1a4702c4bbc6d420eb65d92af44c60c","826ecca0e2837860a6d2be89a410ff6aab22c5f5a66bd0a318de3abe646aa26a","bad663aa8253c40d00de0a2d1dfca60f","4a04d7"}},
{442750, {"18267940a2b37c82850f3fb83d935281ee5cc436b0797ec10ca26c9cc3c0ef01","77bdec7bbc4cabd84cc8cf0666e1fdfe299480b9b2a4cf52cc959d728fa899ab","a8807121e33471cf18aa82af4826c9a7","d35d35"}},
{464350, {"9ab50223bfecec2508e8233540dc13c3fc7e15a8d77ecb90939afee96859724d","675a1b3f2a2cd2bd0e7ec073c426125d95e12ad13e541bf019925c481c2bca15","591d2f2331832c347654ab255ad97e2d","d87c9c"}},
{485950, {"c0d7299fe0b873687e7319f1a0d1f67712ef3ccf6a579d96c5f99743add6f029","dd3d17b5145b56377e023c169ae858cdf48bd6c23e8b2a77e02765ce316e3ca7","6a9e74df01762e2b32db1dc4d69dc3e9","75debe"}}
};
// Hash domain separators
@@ -430,22 +425,14 @@ 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, {"71336a480440ed24a53b2cfd5a5292d1e618c3e843637227883ea2cc42fb346f","a135f59a05ea9e33539e4502b187b4789cc7fba79616c6902a902cc6601f0359","7f1c6970232254a9b13f7f063df2a853","62073c"}},
{1120, {"2cc49b182addc0106b601c9876c01a4b06532c05f9dd9179b2c4f47e5c7c0d74","fd62e59324389f37d0bb628a39f413c11be34d572ec3a40f465e008b9dfd5e0c","fbf8584222e299bb748009eaf2177123","b76a8d"}},
{1140, {"50f1dd5244bb6fdc62b5a18b868a4dc9e9ad15f4a7a54e5a98084a3a5213c846","942de90a3347df3e962d9b0a2745f8aedb265a8caf73aabef9aa713f4ec3e493","933702e29d680bf21ad559a2d3243621","dae32b"}},
{1160, {"114a1fef3a03c81b3b6308fb4e51db42d86945d8f71ee8798749a4aa2d8bfe57","fd77f0289b7e25ae68c86f4cd2c72ac0211a4d0e7a31c84b8d58a33bbd3c511b","d8048bb76b9313768a4c69100cba6d43","46b0a3"}},
{1180, {"cf7fe9d97a7a4cb881bff1d37bb6981bcb0691649c465d660522a43f14b32849","b76908d56108e7111374f60993e9411def7bb2899118f20f49e67a801936a1ad","f203a5acd48f93f1451d32d70716e585","d72097"}},
{1200, {"415e8fa4fb6bed8bc59591883f5e098dde6179e980eccfc4cbb3a64c4168cf47","5426c588d7c5750c76b526ef268b45f7414e2ddea40218ee92d123564c5114c4","fb1926bbef8c70ebd796ae77dffca07d","351edf"}},
{1220, {"1f47cce00e8e1c77cb3ff007491d261dae75de5bbfdbe0f4913d74a8503aaa5e","4d8aac299306989aa169982d89457852a1bab858c668c9b740d96b682bb1961b","d8c0be7926ce704290cfd8d5e0500f33","750003"}},
{1240, {"3afd93c684638d54e68f5d8d417863035f12482251feea5cf7515725a2bb0f4f","7895e6baded473b093b57993ae3497a47b0ea78cf35b37d1387f226f445d9018","76a0c37e6f3d9d508c4bce1d7162514e","09e146"}}
};
}
+266 -65
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,21 @@ 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");
// Work out what the HF version _was_ when the STAKE outputs were created
uint64_t stake_lock_period = get_config(m_nettype).STAKE_LOCK_PERIOD;
uint8_t hf_version_submitted = get_ideal_hard_fork_version(height - stake_lock_period - 1);
if (hf_version >= HF_VERSION_CARROT) {
if (hf_version_submitted >= HF_VERSION_CARROT || b.protocol_tx.vout.size() == 0) {
CHECK_AND_ASSERT_MES(b.protocol_tx.version == TRANSACTION_VERSION_CARROT, false, "protocol transaction has wrong version");
} else {
CHECK_AND_ASSERT_MES(b.protocol_tx.version == 2, false, "protocol transaction has wrong version");
}
CHECK_AND_ASSERT_MES(b.protocol_tx.type == cryptonote::transaction_type::PROTOCOL, false, "protocol transaction has wrong type");
} else {
hf_version_submitted = hf_version;
}
// 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)
{
@@ -1418,8 +1438,7 @@ bool Blockchain::prevalidate_protocol_transaction(const block& b, uint64_t heigh
return false;
}
CHECK_AND_ASSERT_MES(check_output_types(b.protocol_tx, hf_version), false, "protocol transaction has invalid output type(s) in block " << get_block_hash(b));
CHECK_AND_ASSERT_MES(check_output_types(b.protocol_tx, hf_version_submitted), false, "protocol transaction has invalid output type(s) in block " << get_block_hash(b));
return true;
}
//------------------------------------------------------------------
@@ -1427,8 +1446,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 +1455,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 +1582,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 +1591,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 (get_ideal_hard_fork_version(matured_height) >= 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 +1634,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 +1942,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
@@ -1905,36 +1990,69 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
cryptonote::yield_block_info ybi_matured;
bool ok = get_ybi_entry(start_height, ybi_matured);
if (ok && ybi_matured.locked_coins_this_block > 0) {
// 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;
}
// 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";
// Iterate over the cached data for block yield, calculating the yield payouts due
std::vector<std::pair<yield_tx_info, uint64_t>> yield_payouts;
std::vector<std::pair<yield_tx_info_carrot, uint64_t>> carrot_yield_payouts;
if (hf_submitted >= 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;
}
}
// Create the protocol_metadata entries here
if (!carrot_yield_payouts.empty()) {
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;
entry.is_carrot = true;
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;
entry.is_carrot = false;
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);
}
}
@@ -1978,6 +2096,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
entry.P_change = audit_entry.first.P_change;
entry.return_pubkey = audit_entry.first.return_pubkey;
entry.origin_height = matured_audit_height;
entry.is_carrot = false;
protocol_entries.push_back(entry);
}
}
@@ -2355,7 +2474,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 +3727,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));
@@ -3683,7 +3802,7 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
}
// Check for v1 TXs - genesis block protocol_tx exception required!
if (tx.version == 1 && epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(tx)) == "4f78ff511e860acd03138737a71505eb62eb78b620e180e58c8e13ed0e1e3e19") {
if (tx.version == 1) {
MERROR("v1 TXs are not permitted");
tvc.m_version_mismatch = true;
return false;
@@ -3691,7 +3810,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 +3818,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) {
@@ -3708,6 +3835,32 @@ bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verificatio
}
}
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Make sure we are supposed to accept AUDIT txs at this point
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
CHECK_AND_ASSERT_MES(audit_hard_forks.find(hf_version) != audit_hard_forks.end(), false, "trying to audit outside an audit fork");
std::string expected_asset_type = audit_hard_forks.at(hf_version).second.first;
CHECK_AND_ASSERT_MES(tx.source_asset_type == expected_asset_type, false, "trying to spend " << tx.source_asset_type << " coins in an AUDIT TX");
} else {
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL1", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
} else {
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
}
}
if (tx.type == cryptonote::transaction_type::BURN) {
CHECK_AND_ASSERT_MES(tx.destination_asset_type == "BURN", false, "incorrect burn tx destination type:" << tx.destination_asset_type);
} else {
if (tx.source_asset_type != tx.destination_asset_type) {
MERROR_VER("Tx " << get_transaction_hash(tx) << " has mismatched asset types: " << tx.source_asset_type << " != " << tx.destination_asset_type);
tvc.m_verifivation_failed = true;
return false;
}
}
// Check for invalid TX types
if (tx.type == cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) {
MERROR("TX type `" + std::to_string(tx.type) + "' is not supported");
@@ -3742,7 +3895,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 +4094,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)
{
@@ -3979,20 +4124,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
}
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Make sure we are supposed to accept AUDIT txs at this point
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(m_nettype).AUDIT_HARD_FORKS;
CHECK_AND_ASSERT_MES(audit_hard_forks.find(hf_version) != audit_hard_forks.end(), false, "trying to audit outside an audit fork");
std::string expected_asset_type = audit_hard_forks.at(hf_version).second.first;
CHECK_AND_ASSERT_MES(tx.source_asset_type == expected_asset_type, false, "trying to spend " << tx.source_asset_type << " coins in an AUDIT TX");
} else {
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL1", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
} else {
CHECK_AND_ASSERT_MES(tx.source_asset_type == "SAL", false, "trying to spend " << tx.source_asset_type << " coins in a non-AUDIT TX");
}
}
std::vector<std::vector<rct::ctkey>> pubkeys(tx.vin.size());
std::vector < uint64_t > results;
results.resize(tx.vin.size(), 0);
@@ -4582,6 +4713,72 @@ 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 for carrot, 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;
uint64_t yield_u64 = boost::numeric_cast<uint64_t>(yield_128);
if (entry.second + yield_u64 < entry.second) {
throw std::overflow_error("uint64_t addition overflow");
}
entry.second += yield_u64;
}
}
// 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__);
@@ -4632,10 +4829,14 @@ bool Blockchain::calculate_yield_payouts(const uint64_t start_height, std::vecto
// 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>();
uint64_t yield_u64 = boost::numeric_cast<uint64_t>(yield_128);
if (entry.second + yield_u64 < entry.second) {
throw std::overflow_error("uint64_t addition overflow");
}
entry.second += yield_u64;
}
}
@@ -6313,7 +6514,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "a2a5a9bc5d606392ac5c14be55b90a92b8577b8ffdac5c63cc6174f41764c753";
static const char expected_block_hashes_hash[] = "1cf6e8892e0512c246cef62610ccf524f30f484e307ae01959a5a7dd166aa328";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
+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
*
+4 -2
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
@@ -1020,7 +1022,7 @@ namespace cryptonote
}
if (!rvv.empty())
{
LOG_PRINT_L1("One transaction among this group has bad semantics, verifying one at a time");
LOG_PRINT_L1("Verifying transactions one at a time");
ret = false;
for (size_t n = 0; n < tx_info.size(); ++n)
{
+59 -35
View File
@@ -346,14 +346,30 @@ namespace cryptonote
// Clear the TX contents
tx.set_null();
tx.version = 2;
bool carrot_found = false;
bool noncarrot_found = false;
tx.type = cryptonote::transaction_type::PROTOCOL;
// Force the TX type to 2
tx.version = 2;
const bool do_carrot = hard_fork_version >= HF_VERSION_CARROT;
if (do_carrot)
// Scan the protocol_data to make sure all or none are Carrot
for (auto const& entry: protocol_data) {
if (entry.is_carrot) carrot_found = true;
else noncarrot_found = true;
}
if (carrot_found && noncarrot_found) {
LOG_ERROR("Cannot mix Carrot and non-Carrot outputs in the same protocol transaction");
return false;
}
if (carrot_found && hard_fork_version < HF_VERSION_CARROT) {
LOG_ERROR("Carrot outputs found in CryptoNote protocol transaction");
return false;
}
if (carrot_found || (!noncarrot_found && hard_fork_version >= HF_VERSION_CARROT))
{
// Ensure the TX version is correct
tx.version = TRANSACTION_VERSION_CARROT;
try
{
// Create a vector of enotes
@@ -362,32 +378,17 @@ 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);
}
tx = store_carrot_to_coinbase_transaction_v1(enotes, std::string{}, cryptonote::transaction_type::PROTOCOL, height);
tx.amount_burnt = 0;
tx.invalidate_hashes();
@@ -410,14 +411,29 @@ namespace cryptonote
std::vector<crypto::public_key> additional_tx_public_keys;
for (auto const& entry: protocol_data) {
if (entry.type == cryptonote::transaction_type::STAKE) {
// PAYOUT
LOG_PRINT_L2("Yield TX payout submitted " << entry.amount_burnt << entry.source_asset);
if (entry.is_carrot) {
tx_out out;
out.amount = entry.amount_burnt;
out.target = txout_to_carrot_v1 {
.key = entry.return_address,
.asset_type = entry.destination_asset,
.view_tag = entry.return_view_tag,
.encrypted_janus_anchor = entry.return_anchor_enc,
};
// Create the TX output for this refund
tx_out out;
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
} else {
// Create the TX output for this refund
tx_out out;
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
}
} else if (entry.type == cryptonote::transaction_type::AUDIT) {
// PAYOUT
LOG_PRINT_L2("Audit TX payout submitted " << entry.amount_burnt << entry.source_asset);
@@ -1424,16 +1440,24 @@ namespace cryptonote
bool get_block_longhash(const Blockchain *pbc, const blobdata& bd, crypto::hash& res, const uint64_t height, const int major_version, const crypto::hash *seed_hash, const int miners)
{
crypto::hash hash;
if (pbc != NULL)
{
crypto::hash hash;
const uint64_t seed_height = rx_seedheight(height);
hash = seed_hash ? *seed_hash : pbc->get_pending_block_id_by_height(seed_height);
rx_slow_hash(hash.data, bd.data(), bd.size(), res.data);
} else
{
memset(&hash, 0, sizeof(hash)); // only happens when generating genesis block
// only happens when generating genesis block
// Hardcoded genesis for ios compat
const char* hex = "4ade63d5ccb8cfae075e8b882514c471f35da95f85dd1b20fdcd6f3a95caabc5";
char bytes[32];
for (int i = 0; i < 32; i++) {
char byte_str[3] = { hex[i * 2], hex[i * 2 + 1], '\0' };
bytes[i] = (char)strtol(byte_str, NULL, 16);
}
memcpy(res.data, bytes, sizeof(bytes));
}
rx_slow_hash(hash.data, bd.data(), bd.size(), res.data);
return true;
}
@@ -68,7 +68,10 @@ namespace cryptonote
uint8_t type;
crypto::public_key P_change;
crypto::public_key return_pubkey;
carrot::view_tag_t return_view_tag;
carrot::encrypted_janus_anchor_t return_anchor_enc;
uint64_t origin_height;
bool is_carrot;
};
//---------------------------------------------------------------
+10
View File
@@ -1749,6 +1749,16 @@ namespace cryptonote
LOG_PRINT_L2(" key images already seen");
continue;
}
if (version < HF_VERSION_CARROT && tx.version >= TRANSACTION_VERSION_CARROT)
{
LOG_PRINT_L2(" is a Carrot transaction - cannot be mined");
continue;
}
if (version >= HF_VERSION_CARROT && tx.version < TRANSACTION_VERSION_CARROT)
{
LOG_PRINT_L2(" is not a Carrot transaction - cannot be mined");
continue;
}
bl.tx_hashes.push_back(sorted_it->second);
total_weight += meta.weight;
@@ -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();
+4 -2
View File
@@ -29,10 +29,11 @@
set(device_sources
device.cpp
device_default.cpp
device_io_dummy.cpp
log.cpp
)
if(HIDAPI_FOUND)
if(HIDAPI_FOUND OR HIDAPI_DUMMY)
set(device_sources
${device_sources}
device_ledger.cpp
@@ -45,10 +46,11 @@ set(device_headers
device_io.hpp
device_default.hpp
device_cold.hpp
device_io_dummy.hpp
log.hpp
)
if(HIDAPI_FOUND)
if(HIDAPI_FOUND OR HIDAPI_DUMMY)
set(device_headers
${device_headers}
device_ledger.hpp
+6 -4
View File
@@ -29,7 +29,7 @@
#include "device.hpp"
#include "device_default.hpp"
#ifdef WITH_DEVICE_LEDGER
#if defined(WITH_DEVICE_LEDGER) || defined(HIDAPI_DUMMY)
#include "device_ledger.hpp"
#endif
#include "misc_log_ex.h"
@@ -57,7 +57,7 @@ namespace hw {
device_registry::device_registry(){
hw::core::register_all(registry);
#ifdef WITH_DEVICE_LEDGER
#if defined(WITH_DEVICE_LEDGER) || defined(HIDAPI_DUMMY)
hw::ledger::register_all(registry);
#endif
atexit(clear_device_registry);
@@ -83,11 +83,13 @@ namespace hw {
auto device = registry.find(device_descriptor_lookup);
if (device == registry.end()) {
MERROR("Device not found in registry: '" << device_descriptor << "'. Known devices: ");
std::stringstream ss("Device not found in registry: '" + device_descriptor + "'. Known devices: ");
MERROR("Device not found in registry: '" << device_descriptor << "'. Known devices: \n");
for( const auto& sm_pair : registry ) {
ss << "\n- " + sm_pair.first;
MERROR(" - " << sm_pair.first);
}
throw std::runtime_error("device not found: " + device_descriptor);
throw std::runtime_error("device not found: " + device_descriptor + "\n" + ss.str());
}
return *device->second;
}
+1 -11
View File
@@ -34,17 +34,7 @@
#include "ringct/rctTypes.h"
#include "cryptonote_config.h"
#ifndef USE_DEVICE_LEDGER
#define USE_DEVICE_LEDGER 1
#endif
#if !defined(HAVE_HIDAPI)
#undef USE_DEVICE_LEDGER
#define USE_DEVICE_LEDGER 0
#endif
#if USE_DEVICE_LEDGER
#if defined(HAVE_HIDAPI) || defined(HIDAPI_DUMMY)
#define WITH_DEVICE_LEDGER
#endif
+161
View File
@@ -0,0 +1,161 @@
// Copyright (c) 2017-2022, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// device_io_dummy
// Main goal of device_io_dummy is to emulate a hw::io::device_io without the need to actually
// connect a device.
// Many operating systems do not support giving raw USB access to a process (android), or don't
// support that at all (hi iOS), therefore other means of connection can be used, either USB
// abstraction provided by the OS (monerujo), or BLE (also monerujo).
// Monerujo implementation is written in Java, which makes it a nice fit for iOS, but makes the
// code extremely unportable, so for this reason the code in here is written in CPP.
// Data transport is made available in wallet2_api.h, so wallet developers can easily plug their
// own USB/BLE/other transport layer.
#if defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)
#include <boost/scope_exit.hpp>
#include "log.hpp"
#include "device_io_dummy.hpp"
#include "device_ledger.hpp"
bool hw::io::device_io_dummy::stateIsConnected = false;
unsigned char* hw::io::device_io_dummy::sendToDevice = {};
size_t hw::io::device_io_dummy::sendToDeviceLength = 0;
unsigned char* hw::io::device_io_dummy::receivedFromDevice = {};
size_t hw::io::device_io_dummy::receivedFromDeviceLength = 0;
bool hw::io::device_io_dummy::waitsForDeviceSend = false;
bool hw::io::device_io_dummy::waitsForDeviceReceive = false;
void (*hw::io::device_io_dummy::sendToLedgerDeviceCallback)(unsigned char *command, unsigned int cmd_len) = nullptr;
std::mutex hw::io::device_io_dummy::mutex;
std::condition_variable hw::io::device_io_dummy::cv_send;
std::condition_variable hw::io::device_io_dummy::cv_receive;
namespace hw {
namespace io {
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "device.io_dummy"
device_io_dummy::device_io_dummy(int a, int b, int c, int d) {
MDEBUG("device_io_dummy(a: " << a << ", b: " << b << ", c: " << c << ", d: " << d <<")");
}
void device_io_dummy::init() {
MDEBUG("init()");
}
void device_io_dummy::connect(void *params) {
MDEBUG("connect(" << params << ")");
stateIsConnected = true;
}
void device_io_dummy::connect(const std::vector<hw::io::hid_conn_params>& known_devices) {
MDEBUG("connect([");
for (const auto &item: known_devices) {
MDEBUG("{ interface_number: " << item.interface_number);
MDEBUG(" pid : " << item.pid);
MDEBUG(" usage_page : " << item.usage_page);
MDEBUG(" vid : " << item.vid << " },");
}
MDEBUG("])");
stateIsConnected = true;
}
bool device_io_dummy::connected() const {
MDEBUG("connected()");
return stateIsConnected;
}
int device_io_dummy::exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len, bool user_input) {
MDEBUG("exchange(): locking mutex");
std::unique_lock<std::mutex> lock(mutex);
sendToDevice = command;
sendToDeviceLength = cmd_len;
waitsForDeviceSend = true;
waitsForDeviceReceive = true;
// Call the callback if it's set
if (sendToLedgerDeviceCallback != nullptr) {
MDEBUG("exchange(): calling sendToLedgerDeviceCallback");
sendToLedgerDeviceCallback(command, cmd_len);
}
MDEBUG("exchange(): waitsForDeviceSend");
// Wait for the send flag to be cleared by external code
while (waitsForDeviceSend) {
cv_send.wait(lock);
MDEBUG("exchange(): waitsForDeviceSend notified");
}
MDEBUG("exchange(): waitsForDeviceReceive");
// Wait for the receive flag to be cleared by external code
while (waitsForDeviceReceive) {
cv_receive.wait(lock);
MDEBUG("exchange(): waitsForDeviceReceive notified");
}
if (receivedFromDeviceLength > max_resp_len) {
MDEBUG("exchange(): receivedFromDeviceLength ("<<receivedFromDeviceLength<<") is larger than max_resp_len ("<<max_resp_len<<")");
return 1;
}
memset(response, 0, max_resp_len);
memcpy(response, receivedFromDevice, receivedFromDeviceLength);
return receivedFromDeviceLength;
}
void device_io_dummy::disconnect() {
MDEBUG("disconnect()");
}
void device_io_dummy::release() {
MDEBUG("release()");
}
void device_io_dummy::setLedgerCallback(void (*sendToLedgerDevice)(unsigned char *command, unsigned int cmd_len)) {
MDEBUG("setLedgerCallback()");
sendToLedgerDeviceCallback = sendToLedgerDevice;
}
void device_io_dummy::setDeviceReceivedData(unsigned char* data, size_t len) {
MDEBUG("setDeviceReceivedData(len: " << len << ")");
std::unique_lock<std::mutex> lock(mutex);
receivedFromDevice = static_cast<unsigned char *>(malloc(len));
receivedFromDeviceLength = len;
memset(receivedFromDevice, 0, len);
memcpy(receivedFromDevice, data, len);
waitsForDeviceReceive = false;
waitsForDeviceSend = false;
cv_send.notify_all();
cv_receive.notify_all();
}
}
}
#endif // HAVE_HIDAPI
+82
View File
@@ -0,0 +1,82 @@
// Copyright (c) 2017-2022, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifdef HIDAPI_DUMMY
#pragma once
#include "device_io.hpp"
#include "device_io_hid.hpp"
#include <mutex>
#include <condition_variable>
namespace hw {
namespace io {
struct hid_conn_params {
unsigned int vid;
unsigned int pid;
int interface_number;
unsigned short usage_page;
};
class device_io_dummy : device_io {
private:
static std::mutex mutex;
public:
static std::condition_variable cv_send;
static std::condition_variable cv_receive;
static bool stateIsConnected;
static unsigned char* sendToDevice;
static size_t sendToDeviceLength;
static unsigned char* receivedFromDevice;
static size_t receivedFromDeviceLength;
static bool waitsForDeviceSend;
static bool waitsForDeviceReceive;
static void (*sendToLedgerDeviceCallback)(unsigned char *command, unsigned int cmd_len);
device_io_dummy() = default;
device_io_dummy(int a, int b, int c, int d);
~device_io_dummy() = default;
void init();
void release();
void connect(void *parms);
void connect(const std::vector<hw::io::hid_conn_params>& known_devices);
void disconnect();
bool connected() const;
int exchange(unsigned char *command, unsigned int cmd_len, unsigned char *response, unsigned int max_resp_len, bool user_input);
static void setLedgerCallback(void (*sendToLedgerDevice)(unsigned char *command, unsigned int cmd_len));
static void setDeviceReceivedData(unsigned char* data, size_t len);
};
};
};
#endif // HAVE_HIDAPI
+4 -2
View File
@@ -38,7 +38,7 @@ namespace hw {
namespace ledger {
#ifdef WITH_DEVICE_LEDGER
#if defined(WITH_DEVICE_LEDGER) || defined(HIDAPI_DUMMY)
namespace {
bool apdu_verbose =true;
@@ -300,7 +300,7 @@ namespace hw {
device_ledger::device_ledger(): hw_device(0x0101, 0x05, 64, 2000) {
this->id = device_id++;
this->reset_buffer();
this->reset_buffer();
this->mode = NONE;
this->has_view_key = false;
this->tx_in_progress = false;
@@ -533,7 +533,9 @@ namespace hw {
bool device_ledger::connect(void) {
this->disconnect();
#if !(defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI))
hw_device.connect(known_devices);
#endif
this->reset();
#ifdef DEBUG_HWDEVICE
cryptonote::account_public_address pubkey;
+6 -1
View File
@@ -35,6 +35,7 @@
#include "device.hpp"
#include "log.hpp"
#include "device_io_hid.hpp"
#include "device_io_dummy.hpp"
#include <mutex>
namespace hw {
@@ -55,7 +56,7 @@ namespace hw {
void register_all(std::map<std::string, std::unique_ptr<device>> &registry);
#ifdef WITH_DEVICE_LEDGER
#if defined(WITH_DEVICE_LEDGER) || defined(HIDAPI_DUMMY)
// Origin: https://github.com/LedgerHQ/ledger-app-monero/blob/master/src/monero_types.h
#define SW_OK 0x9000
@@ -143,7 +144,11 @@ namespace hw {
mutable std::mutex command_locker;
//IO
#if defined(HIDAPI_DUMMY) && !defined(HAVE_HIDAPI)
hw::io::device_io_dummy hw_device;
#else
hw::io::device_io_hid hw_device;
#endif
unsigned int length_send;
unsigned char buffer_send[BUFFER_SEND_SIZE];
unsigned int length_recv;
+3
View File
@@ -58,6 +58,9 @@ const hardfork_t mainnet_hard_forks[] = {
// version 9 starts from block 179200, which is on or around the 10th of March, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v9 fork.
{ 9, 179200, 0, 1740393800 },
// version 10 Carrot - including treasury mint - starts from block 334750, which is on or around the 13th of October, 2025. Fork time finalised on 2025-09-29. No fork voting occurs for the v10 fork.
{10, 334750, 0, 1759142500 },
};
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1);
+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)
{
+25
View File
@@ -0,0 +1,25 @@
set(polyseed_sources
pbkdf2.c
polyseed.cpp
)
monero_find_all_headers(polyseed_private_headers "${CMAKE_CURRENT_SOURCE_DIR}")
monero_private_headers(polyseed_wrapper
${polyseed_private_headers}
)
monero_add_library(polyseed_wrapper
${polyseed_sources}
${polyseed_headers}
${polyseed_private_headers}
)
target_link_libraries(polyseed_wrapper
PUBLIC
polyseed
utf8proc
${SODIUM_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES}
)
+85
View File
@@ -0,0 +1,85 @@
// Copyright (c) 2023, The Monero Project
// Copyright (c) 2021, tevador <tevador@gmail.com>
// Copyright (c) 2005,2007,2009 Colin Percival
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
#include <string.h>
#include <sodium/crypto_auth_hmacsha256.h>
#include <sodium/utils.h>
static inline void
store32_be(uint8_t dst[4], uint32_t w)
{
dst[3] = (uint8_t) w; w >>= 8;
dst[2] = (uint8_t) w; w >>= 8;
dst[1] = (uint8_t) w; w >>= 8;
dst[0] = (uint8_t) w;
}
void
crypto_pbkdf2_sha256(const uint8_t* passwd, size_t passwdlen,
const uint8_t* salt, size_t saltlen, uint64_t c,
uint8_t* buf, size_t dkLen)
{
crypto_auth_hmacsha256_state Phctx, PShctx, hctx;
size_t i;
uint8_t ivec[4];
uint8_t U[32];
uint8_t T[32];
uint64_t j;
int k;
size_t clen;
crypto_auth_hmacsha256_init(&Phctx, passwd, passwdlen);
PShctx = Phctx;
crypto_auth_hmacsha256_update(&PShctx, salt, saltlen);
for (i = 0; i * 32 < dkLen; i++) {
store32_be(ivec, (uint32_t)(i + 1));
hctx = PShctx;
crypto_auth_hmacsha256_update(&hctx, ivec, 4);
crypto_auth_hmacsha256_final(&hctx, U);
memcpy(T, U, 32);
for (j = 2; j <= c; j++) {
hctx = Phctx;
crypto_auth_hmacsha256_update(&hctx, U, 32);
crypto_auth_hmacsha256_final(&hctx, U);
for (k = 0; k < 32; k++) {
T[k] ^= U[k];
}
}
clen = dkLen - i * 32;
if (clen > 32) {
clen = 32;
}
memcpy(&buf[i * 32], T, clen);
}
sodium_memzero((void*)&Phctx, sizeof Phctx);
sodium_memzero((void*)&PShctx, sizeof PShctx);
}
+46
View File
@@ -0,0 +1,46 @@
// Copyright (c) 2023, The Monero Project
// Copyright (c) 2021, tevador <tevador@gmail.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
#ifndef PBKDF2_H
#define PBKDF2_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void
crypto_pbkdf2_sha256(const uint8_t* passwd, size_t passwdlen,
const uint8_t* salt, size_t saltlen, uint64_t c,
uint8_t* buf, size_t dkLen);
#ifdef __cplusplus
}
#endif
#endif
+182
View File
@@ -0,0 +1,182 @@
// Copyright (c) 2023, The Monero Project
// Copyright (c) 2021, tevador <tevador@gmail.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
#include "polyseed.hpp"
#include "pbkdf2.h"
#include <sodium/core.h>
#include <sodium/utils.h>
#include <sodium/randombytes.h>
#include <utf8proc.h>
#include <cstring>
#include <algorithm>
#include <array>
namespace polyseed {
inline size_t utf8_norm(const char* str, polyseed_str norm, utf8proc_option_t options) {
utf8proc_int32_t buffer[POLYSEED_STR_SIZE];
utf8proc_ssize_t result;
result = utf8proc_decompose(reinterpret_cast<const uint8_t*>(str), 0, buffer, POLYSEED_STR_SIZE, options);
if (result < 0 || result > (POLYSEED_STR_SIZE - 1)) {
throw std::runtime_error("Unicode normalization failed");
}
result = utf8proc_reencode(buffer, result, options);
if (result < 0 || result > POLYSEED_STR_SIZE) {
throw std::runtime_error("Unicode normalization failed");
}
strcpy(norm, reinterpret_cast<const char*>(buffer));
sodium_memzero(buffer, POLYSEED_STR_SIZE);
return result;
}
static size_t utf8_nfc(const char* str, polyseed_str norm) {
// Note: UTF8PROC_LUMP is used here to replace the ideographic space with a regular space for Japanese phrases
// to allow wallets to split on ' '.
return utf8_norm(str, norm, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_COMPOSE | UTF8PROC_STRIPNA));
}
static size_t utf8_nfkd(const char* str, polyseed_str norm) {
return utf8_norm(str, norm, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE | UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT | UTF8PROC_STRIPNA));
}
struct dependency {
dependency();
std::vector<language> languages;
};
static dependency deps;
dependency::dependency() {
if (sodium_init() == -1) {
throw std::runtime_error("sodium_init failed");
}
polyseed_dependency pd;
pd.randbytes = &randombytes_buf;
pd.pbkdf2_sha256 = &crypto_pbkdf2_sha256;
pd.memzero = &sodium_memzero;
pd.u8_nfc = &utf8_nfc;
pd.u8_nfkd = &utf8_nfkd;
pd.time = nullptr;
pd.alloc = nullptr;
pd.free = nullptr;
polyseed_inject(&pd);
for (int i = 0; i < polyseed_get_num_langs(); ++i) {
languages.push_back(language(polyseed_get_lang(i)));
}
}
static language invalid_lang;
const std::vector<language>& get_langs() {
return deps.languages;
}
const language& get_lang_by_name(const std::string& name) {
for (auto& lang : deps.languages) {
if (name == lang.name_en()) {
return lang;
}
if (name == lang.name()) {
return lang;
}
}
return invalid_lang;
}
inline void data::check_init() const {
if (valid()) {
throw std::runtime_error("already initialized");
}
}
static std::array<const char*, 8> error_desc = {
"Success",
"Wrong number of words in the phrase",
"Unknown language or unsupported words",
"Checksum mismatch",
"Unsupported seed features",
"Invalid seed format",
"Memory allocation failure",
"Unicode normalization failed"
};
static error get_error(polyseed_status status) {
if (status > 0 && status < sizeof(error_desc) / sizeof(const char*)) {
return error(error_desc[(int)status], status);
}
return error("Unknown error", status);
}
void data::create(feature_type features) {
check_init();
auto status = polyseed_create(features, &m_data);
if (status != POLYSEED_OK) {
throw get_error(status);
}
}
void data::split(const language& lang, polyseed_phrase& words) {
check_init();
if (!lang.valid()) {
throw std::runtime_error("invalid language");
}
}
void data::load(polyseed_storage storage) {
check_init();
auto status = polyseed_load(storage, &m_data);
if (status != POLYSEED_OK) {
throw get_error(status);
}
}
void data::load(const crypto::secret_key &key) {
polyseed_storage d;
memcpy(&d, &key.data, 32);
auto status = polyseed_load(d, &m_data);
if (status != POLYSEED_OK) {
throw get_error(status);
}
}
language data::decode(const char* phrase) {
check_init();
const polyseed_lang* lang;
auto status = polyseed_decode(phrase, m_coin, &lang, &m_data);
if (status != POLYSEED_OK) {
throw get_error(status);
}
return language(lang);
}
}
+167
View File
@@ -0,0 +1,167 @@
// Copyright (c) 2023, The Monero Project
// Copyright (c) 2021, tevador <tevador@gmail.com>
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
#ifndef POLYSEED_HPP
#define POLYSEED_HPP
#include <polyseed/include/polyseed.h>
#include <polyseed/src/lang.h>
#include <vector>
#include <stdexcept>
#include <string>
#include "crypto/crypto.h"
namespace polyseed {
class data;
class language {
public:
language() : m_lang(nullptr) {}
language(const language&) = default;
language(const polyseed_lang* lang) : m_lang(lang) {}
const char* name() const {
return polyseed_get_lang_name(m_lang);
}
const char* name_en() const {
return polyseed_get_lang_name_en(m_lang);
}
const char* separator() const {
return m_lang->separator;
}
bool valid() const {
return m_lang != nullptr;
}
const polyseed_lang* m_lang;
private:
friend class data;
};
const std::vector<language>& get_langs();
const language& get_lang_by_name(const std::string& name);
class error : public std::runtime_error {
public:
error(const char* msg, polyseed_status status)
: std::runtime_error(msg), m_status(status)
{
}
polyseed_status status() const {
return m_status;
}
private:
polyseed_status m_status;
};
using feature_type = unsigned int;
inline int enable_features(feature_type features) {
return polyseed_enable_features(features);
}
class data {
public:
data(const data&) = delete;
data(polyseed_coin coin) : m_data(nullptr), m_coin(coin) {}
~data() {
polyseed_free(m_data);
}
void create(feature_type features);
void load(polyseed_storage storage);
void load(const crypto::secret_key &key);
language decode(const char* phrase);
template<class str_type>
void encode(const language& lang, str_type& str) const {
check_valid();
if (!lang.valid()) {
throw std::runtime_error("invalid language");
}
str.resize(POLYSEED_STR_SIZE);
auto size = polyseed_encode(m_data, lang.m_lang, m_coin, &str[0]);
str.resize(size);
}
void split(const language& lang, polyseed_phrase& words);
void save(polyseed_storage storage) const {
check_valid();
polyseed_store(m_data, storage);
}
void save(void *storage) const {
check_valid();
polyseed_store(m_data, (uint8_t*)storage);
}
void crypt(const char* password) {
check_valid();
polyseed_crypt(m_data, password);
}
void keygen(void* ptr, size_t key_size) const {
check_valid();
polyseed_keygen(m_data, m_coin, key_size, (uint8_t*)ptr);
}
bool valid() const {
return m_data != nullptr;
}
bool encrypted() const {
check_valid();
return polyseed_is_encrypted(m_data);
}
uint64_t birthday() const {
check_valid();
return polyseed_get_birthday(m_data);
}
bool has_feature(feature_type feature) const {
check_valid();
return polyseed_get_feature(m_data, feature) != 0;
}
private:
void check_valid() const {
if (m_data == nullptr) {
throw std::runtime_error("invalid object");
}
}
void check_init() const;
polyseed_data* m_data;
polyseed_coin m_coin;
};
}
#endif //POLYSEED_HPP
+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);

Some files were not shown because too many files have changed in this diff Show More