Compare commits

..

70 Commits

Author SHA1 Message Date
Some Random Crypto Guy 075ba14f9f fix to wallet issue on all transfers _after_ an aborted one; disabled update checking on moneropulse; bumped version number to 0.2.5 2024-06-12 12:48:42 +01:00
Some Random Crypto Guy 126caed899 removed remaining lightwallet code - maybe this time! 2024-06-10 18:30:06 +01:00
Some Random Crypto Guy 3a2be26feb removed remaining lightwallet code 2024-06-10 18:24:01 +01:00
Some Random Crypto Guy aeea005c95 fixed wallet API usage in GUI wallet 2024-06-10 18:12:46 +01:00
somerandomcryptoguy 2a0c17480e Merge pull request #1 from somerandomcryptoguy/rebase-v0.18.3.3
fixed up some missing copyright messages; added unlock_time validatio…
2024-06-10 15:02:45 +01:00
Some Random Crypto Guy 584890ab25 fixed up some missing copyright messages; added unlock_time validation for protocol_tx outputs 2024-06-10 14:54:57 +01:00
Neil Coggins 759531eff5 merged develop into main 2024-06-07 21:25:48 +01:00
Neil Coggins f582757dae Merge branch 'rebase-v0.18.3.3' into develop 2024-06-07 21:22:42 +01:00
Some Random Crypto Guy e69437ca6a added more secure verification of protocol_tx outputs; bumped version number 2024-06-07 17:02:13 +01:00
Neil Coggins 50075e04c3 fixed logging message for adding block to separate out the burnt reward from the block reward 2024-06-07 13:07:11 +01:00
Neil Coggins 7f3dba49a7 Merge branch 'rebase-v0.18.3.3' of https://github.com/somerandomcryptoguy/salvium into rebase-v0.18.3.3 2024-06-06 14:14:52 +01:00
Neil Coggins 9c098ae1fb added support for auto-frozen incoming payments 2024-06-06 14:13:14 +01:00
Some Random Crypto Guy 078fa00bc5 bumped version number 2024-06-05 15:54:06 +01:00
Some Random Crypto Guy 9dc1c429f7 replaced the windows fixes back into the rebased code 2024-06-05 15:52:35 +01:00
Some Random Crypto Guy 8c5a1248b6 added missing files from v0.18.3.3 contrib area 2024-06-05 14:17:15 +01:00
Some Random Crypto Guy d39c20bb2d rebase to 0.18.3.3 completed 2024-06-05 14:03:44 +01:00
Neil Coggins 43eaed7a76 bumped testnet version to prevent Fulmofan from trashing the testnet before it even gets running 2024-05-27 17:01:06 +01:00
Some Random Crypto Guy 32d9edee1a disabled return_payment mechanism for alpha testing 2024-05-27 12:06:06 +01:00
Some Random Crypto Guy c49aacf389 prep for alpha binary release 2024-05-27 11:36:36 +01:00
Some Random Crypto Guy 2726b0556a prep for alpha binary release 2024-05-27 11:35:34 +01:00
Some Random Crypto Guy 2e33174d2e prep for alpha binary release 2024-05-27 11:34:43 +01:00
Some Random Crypto Guy e23423c16d partial fix to the detection of return payments - ECDH is an issue again, but reversion to using F point should resolve this and complete the implementation 2024-05-27 10:38:44 +01:00
ncoggins 42d8dc5ece fixed output of show_transfers, including filtering by TX type; bumped version number 2024-05-20 20:57:10 +01:00
Some Random Crypto Guy 89d426a739 Merge branch 'updated_return_address' into develop 2024-05-20 10:33:48 +01:00
ncoggins 199e47e076 small fix to prevent wallets from abandoning scanning when encountering protocol_tx not intended for them - duh! 2024-05-20 09:28:44 +01:00
Some Random Crypto Guy d24ed9e0cc fixes to the CLI wallet output of staking and protocol_tx outputs 2024-05-18 13:51:10 +01:00
ncoggins 872303f6ad fixed removal of m_locked_coins entries when PROTOCOL_TX pays out 2024-05-18 08:41:54 +01:00
Some Random Crypto Guy c56cfc6754 added versioning to avoid inadvertent use of old nodes 2024-05-17 13:09:57 +01:00
Neil Coggins de4e974e4c resolved MacOS wallet build issues 2024-05-17 11:30:58 +01:00
Some Random Crypto Guy 4607939ab6 fixed unlock time info displayed for mined blocks; added tx_type to get_return_address() call - needed for F point on transfers; bumped version 2024-05-16 22:29:32 +01:00
Some Random Crypto Guy 9a37188885 fixed issue with Hardfork 2; removed PRs from HardFork 1 as unnecessary / slowing the chain down 2024-05-16 10:58:02 +01:00
Some Random Crypto Guy aee0f479c1 changed NETWORK_ID and GENESIS_TX for new Salvium networks; fixed genesis_tx calculation for non-mainnet 2024-05-15 12:58:39 +01:00
Some Random Crypto Guy 9f5e18495b fixed windows build issues 2024-05-14 20:58:18 +01:00
Some Random Crypto Guy ae28c7a900 implementation of yield_info function 2024-05-14 14:23:31 +01:00
Some Random Crypto Guy b0ce6d2969 resolved the yield calculation issue 2024-05-12 22:59:43 +01:00
Some Random Crypto Guy 34b2f9b315 commenced removal of pricing_record touchpoints for MVP release 2024-05-07 14:34:19 +01:00
Some Random Crypto Guy 7bafd2866c a number of fixes; disabled return_payment as the functionality is changing to NOT require returning the same output 2024-03-27 14:50:31 +00:00
Some Random Crypto Guy 606580a173 Interim checkin
This code contains working "return address" semantics for CONVERT and YIELD.
2024-02-16 11:02:11 +00:00
Some Random Crypto Guy a3a7f686f3 Added functions to cache and manage yield calculations
Removed "tx.amount_locked" field - "tx.amount_burnt" is technically correct for all cases.
Removed invalid checkpoint data.
2024-01-30 14:22:46 +00:00
Some Random Crypto Guy a0d2044b5d fixed a bug with serialization of the pricing record when communicating between daemon and wallet for conversions 2024-01-17 14:54:41 +00:00
Some Random Crypto Guy 3a032c58a4 Fixed a number of issues with serialization of pricing_record entries. 2024-01-17 12:43:10 +00:00
Some Random Crypto Guy 8657823a72 Merge branch 'uniqueness' into develop 2024-01-10 23:27:42 +00:00
Some Random Crypto Guy 5ba22c2ec9 Far too many changes to track, but the key ones are:
1. rewrite of the Haven variation of the Pricing Record class to support:
   - versioning of the PR format
   - nested supply_data and asset_data structs
   - verification of the signature using a variable-length string (not R+S)

2. calculation of the slippage tallies for a block in add_block(), so that
   we can work out the yield that is due to be paid out for the block.

Loads of little fixes and cleanups.
2024-01-10 23:21:56 +00:00
Some Random Crypto Guy 6b791a3df2 Improved documentation in the code.
Designed, but not implemented, the mechanism for yield - see db_lmdb.cpp
2023-12-27 19:33:28 +00:00
Some Random Crypto Guy a06b121dde First completed round trip test of sFUL/FUSD -> FULM
After all of the trials and tribulations, we finally have a viable prototype!

The code is working for conversions of all kinds. There are a number of
strange and annoying bugs still present, like the rings in the CLI wallet are
misbehaving at times. But we have a viable product.
2023-12-22 21:43:07 +00:00
Some Random Crypto Guy 6d08d5aabf A whole host of changes to start supporting more unified approach to uniqueness
Lots of refactoring still to be done in the codebase, and currently TRANSFER
method does not work - the daemon does not send the real output for some reason.
Lots still to do - please be patient.
This code is NOT ready for use. Or testing. Or anything else.
2023-12-20 01:06:23 +00:00
Some Random Crypto Guy 8bf55dbfef This code is hacky in the extreme, but it appears to contain a fairly complete
implementation of knaccc's "return address scheme" (for more information on this,
please see https://github.com/monero-project/research-lab/issues/53).

Fulmo's PROTOCOL_TX construct relies on a variation of knaccc's design to be
able to make return payments to individuals.

This code is not commercial-grade - it isn't even safe for alpha testing yet,
but it is operational under at least some circumstances, and the math is correct.

Caveat emptor.
2023-12-14 20:17:36 +00:00
Some Random Crypto Guy f30c8be9c6 Fixed some comments and some debugging statements for improved accuracy. 2023-12-13 14:56:11 +00:00
Some Random Crypto Guy 6787d1d018 This is a big update towards working protocol transactions.
1. The CONVERT TX is creating the necessary information.
2. The PROTOCOL TX is creating the necessary information.
3. The wallet recognises the subaddress (kind of) on incoming amounts.

At present, the PROTOCOL TX outputs are NOT spendable or included in balances.
2023-12-13 14:41:59 +00:00
Some Random Crypto Guy 4955910886 this code is a hot mess of confusion with transfer_details and public_keys being scattered to the four winds. this code is NOT safe to use in its current format 2023-12-07 21:17:04 +00:00
Some Random Crypto Guy 93f589a785 added reporting of balances by asset_type in wallet 2023-11-29 22:27:37 +00:00
Some Random Crypto Guy f433d0d043 improved output formatting, to include asset type; created asset indexing function in wallet 2023-11-28 22:54:26 +00:00
Some Random Crypto Guy ccdbfbe397 with all security checks in place, the code is now accepting protocol_tx outputs as valid in-wallet; only the asset_type is misreported now 2023-11-27 23:06:35 +00:00
Some Random Crypto Guy be8e0f7327 Fixed the key definition for circ_supply to allow duplicate tx_ids
Updated the CLI wallet to remove the "address" parameter from CONVERT.
Reordered processing of CONVERT vs PROTOCOL TXs, so that the PROTOCOL
 TXs have the necessary data to decode the destination address.
2023-11-22 06:25:25 +00:00
Some Random Crypto Guy c1f5dd42e8 change is once again working in the wallet - this only leaves the converted amounts to be paid out, and yield TXs to be supported 2023-11-21 21:22:21 +00:00
Some Random Crypto Guy ef27f6380e updated to support propagation of the transaction type - this was necessary to distinguish between YIELD and TRANSFER type 2023-11-17 17:43:21 +00:00
Some Random Crypto Guy 7f6b8daa49 placeholder checkin because of so many changes having been made - let's use github as a backup site 2023-11-09 18:53:09 +00:00
Some Random Crypto Guy aefeb0f83a so this commit contains a new GENESIS TX with the revised TX format - no pricing_record_height etc. Lots of reworking of tests because of changes to function prototypes, etc 2023-10-27 06:14:59 +01:00
Some Random Crypto Guy 8e2c6a81df the premine now works and is spendable; transfers are now working correctly 2023-10-18 19:59:59 +01:00
Some Random Crypto Guy 0b3633ccdc working premine; empty first version of PROTOCOL_TX in block 2023-10-18 10:48:16 +01:00
Some Random Crypto Guy d186cf95c1 added the initial framework for the Fulmo-specific commands in the CLI wallet; more branding / renaming work 2023-09-14 11:55:29 +01:00
Some Random Crypto Guy 08539345d2 little bit of branding 2023-09-13 17:46:22 +01:00
somerandomcryptoguy 6ab0e31c4a Update README.md - name change for project 2023-08-11 11:13:04 +01:00
Some Random Crypto Guy dac963ca27 added asset_type handling to TX outputs 2023-07-16 22:00:53 +01:00
Some Random Crypto Guy 18ec1ad834 changed trezor version 2023-07-16 22:00:53 +01:00
Some Random Crypto Guy f314cf33b9 changed miniupnp version 2023-07-16 22:00:53 +01:00
Some Random Crypto Guy 5abf72f48a updated supercop to correct branch 2023-07-16 22:00:53 +01:00
Some Random Crypto Guy e92fbbdf46 added external deps 2023-07-16 22:00:53 +01:00
Some Random Crypto Guy bf78bd79a1 initial import of Monero base code 2023-07-16 22:00:52 +01:00
Some Random Crypto Guy 2af40522f9 first commit 2023-07-16 22:00:52 +01:00
239 changed files with 12588 additions and 6745 deletions
-1
View File
@@ -1 +0,0 @@
custom: https://www.getmonero.org/get-started/contributing/
-184
View File
@@ -1,184 +0,0 @@
name: ci/gh-actions/cli
on:
push:
pull_request:
paths-ignore:
- 'docs/**'
- '**/README.md'
# The below variables reduce repetitions across similar targets
env:
REMOVE_BUNDLED_BOOST : rm -rf /usr/local/share/boost
BUILD_DEFAULT_LINUX: |
cmake -S . -B build -D ARCH="default" -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Release && cmake --build build -j3
APT_INSTALL_LINUX: 'sudo apt -y install build-essential cmake libboost-all-dev miniupnpc libunbound-dev graphviz doxygen libunwind8-dev pkg-config libssl-dev libzmq3-dev libsodium-dev libhidapi-dev libnorm-dev libusb-1.0-0-dev libpgm-dev libprotobuf-dev protobuf-compiler ccache'
APT_SET_CONF: |
echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
CCACHE_SETTINGS: |
ccache --max-size=150M
ccache --set-config=compression=true
jobs:
build-macos:
runs-on: macOS-latest
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/cache@v3
with:
path: /Users/runner/Library/Caches/ccache
key: ccache-${{ runner.os }}-build-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-build-
- name: install dependencies
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install boost hidapi openssl zmq libpgm miniupnpc expat libunwind-headers protobuf ccache
- name: build
run: |
${{env.CCACHE_SETTINGS}}
make -j3
build-windows:
runs-on: windows-latest
env:
CCACHE_TEMPDIR: C:\Users\runneradmin\.ccache-temp
CCACHE_DIR: C:\Users\runneradmin\.ccache
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/cache@v3
with:
path: C:\Users\runneradmin\.ccache
key: ccache-${{ runner.os }}-build-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-build-
- uses: msys2/setup-msys2@v2
with:
update: true
install: mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-ccache mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-protobuf-c mingw-w64-x86_64-libusb mingw-w64-x86_64-unbound git
- name: build
run: |
${{env.CCACHE_SETTINGS}}
make release-static-win64 -j2
# See the OS labels and monitor deprecations here:
# https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources
build-ubuntu:
runs-on: ${{ matrix.os }}
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-20.04]
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/cache@v3
with:
path: ~/.ccache
key: ccache-${{ runner.os }}-build-${{ matrix.os }}-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-build-${{ matrix.os }}
- name: remove bundled boost
run: ${{env.REMOVE_BUNDLED_BOOST}}
- name: set apt conf
run: ${{env.APT_SET_CONF}}
- name: update apt
run: sudo apt update
- name: install monero dependencies
run: ${{env.APT_INSTALL_LINUX}}
- name: build
run: |
${{env.CCACHE_SETTINGS}}
${{env.BUILD_DEFAULT_LINUX}}
libwallet-ubuntu:
runs-on: ubuntu-20.04
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- uses: actions/cache@v3
with:
path: ~/.ccache
key: ccache-${{ runner.os }}-libwallet-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-libwallet-
- name: remove bundled boost
run: ${{env.REMOVE_BUNDLED_BOOST}}
- name: set apt conf
run: ${{env.APT_SET_CONF}}
- name: update apt
run: sudo apt update
- name: install monero dependencies
run: ${{env.APT_INSTALL_LINUX}}
- name: build
run: |
${{env.CCACHE_SETTINGS}}
cmake .
make wallet_api -j3
test-ubuntu:
needs: build-ubuntu
runs-on: ubuntu-20.04
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: ccache
uses: actions/cache@v3
with:
path: ~/.ccache
key: ccache-${{ runner.os }}-build-ubuntu-latest-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-build-ubuntu-latest
- name: remove bundled boost
run: ${{env.REMOVE_BUNDLED_BOOST}}
- name: set apt conf
run: ${{env.APT_SET_CONF}}
- name: update apt
run: sudo apt update
- name: install monero dependencies
run: ${{env.APT_INSTALL_LINUX}}
- name: install Python dependencies
run: pip install requests psutil monotonic zmq
- name: tests
env:
CTEST_OUTPUT_ON_FAILURE: ON
DNS_PUBLIC: tcp://9.9.9.9
run: |
${{env.CCACHE_SETTINGS}}
${{env.BUILD_DEFAULT_LINUX}}
cmake --build build --target test
# ARCH="default" (not "native") ensures, that a different execution host can execute binaries compiled elsewhere.
# BUILD_SHARED_LIBS=ON speeds up the linkage part a bit, reduces size, and is the only place where the dynamic linkage is tested.
source-archive:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: archive
run: |
pip install git-archive-all
export VERSION="monero-$(git describe)"
export OUTPUT="$VERSION.tar"
echo "OUTPUT=$OUTPUT" >> $GITHUB_ENV
/home/runner/.local/bin/git-archive-all --prefix "$VERSION/" --force-submodules "$OUTPUT"
- uses: actions/upload-artifact@v3
with:
name: ${{ env.OUTPUT }}
path: /home/runner/work/monero/monero/${{ env.OUTPUT }}
-106
View File
@@ -1,106 +0,0 @@
name: ci/gh-actions/depends
on:
push:
pull_request:
paths-ignore:
- 'docs/**'
- '**/README.md'
env:
APT_SET_CONF: |
echo "Acquire::Retries \"3\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
echo "Acquire::http::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
echo "Acquire::ftp::Timeout \"120\";" | sudo tee -a /etc/apt/apt.conf.d/80-custom
CCACHE_SETTINGS: |
ccache --max-size=150M
ccache --set-config=compression=true
jobs:
build-cross:
runs-on: ubuntu-20.04
env:
CCACHE_TEMPDIR: /tmp/.ccache-temp
strategy:
fail-fast: false
matrix:
toolchain:
- name: "RISCV 64bit"
host: "riscv64-linux-gnu"
packages: "python3 gperf g++-riscv64-linux-gnu"
- name: "ARM v7"
host: "arm-linux-gnueabihf"
packages: "python3 gperf g++-arm-linux-gnueabihf"
- name: "ARM v8"
host: "aarch64-linux-gnu"
packages: "python3 gperf g++-aarch64-linux-gnu"
- name: "i686 Win"
host: "i686-w64-mingw32"
packages: "python3 g++-mingw-w64-i686"
- name: "i686 Linux"
host: "i686-pc-linux-gnu"
packages: "gperf cmake g++-multilib python3-zmq"
- name: "Win64"
host: "x86_64-w64-mingw32"
packages: "cmake python3 g++-mingw-w64-x86-64"
- name: "x86_64 Linux"
host: "x86_64-unknown-linux-gnu"
packages: "gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
- name: "Cross-Mac x86_64"
host: "x86_64-apple-darwin11"
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
- name: "Cross-Mac aarch64"
host: "aarch64-apple-darwin11"
packages: "cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev python3-setuptools-git"
- name: "x86_64 Freebsd"
host: "x86_64-unknown-freebsd"
packages: "clang-8 gperf cmake python3-zmq libdbus-1-dev libharfbuzz-dev"
name: ${{ matrix.toolchain.name }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
# Most volatile cache
- name: ccache
uses: actions/cache@v3
with:
path: ~/.ccache
key: ccache-${{ matrix.toolchain.host }}-${{ github.sha }}
restore-keys: ccache-${{ matrix.toolchain.host }}-
# Less volatile cache
- name: depends cache
uses: actions/cache@v3
with:
path: contrib/depends/built
key: depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
restore-keys: |
depends-${{ matrix.toolchain.host }}-${{ hashFiles('contrib/depends/packages/*') }}
depends-${{ matrix.toolchain.host }}-
# Static cache
- name: OSX SDK cache
uses: actions/cache@v3
with:
path: contrib/depends/sdk-sources
key: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
restore-keys: sdk-${{ matrix.toolchain.host }}-${{ matrix.toolchain.osx_sdk }}
- name: set apt conf
run: ${{env.APT_SET_CONF}}
- name: install dependencies
run: sudo apt update; sudo apt -y install build-essential libtool cmake autotools-dev automake pkg-config bsdmainutils curl git ca-certificates ccache ${{ matrix.toolchain.packages }}
- name: prepare w64-mingw32
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'i686-w64-mingw32' }}
run: |
sudo update-alternatives --set ${{ matrix.toolchain.host }}-g++ $(which ${{ matrix.toolchain.host }}-g++-posix)
sudo update-alternatives --set ${{ matrix.toolchain.host }}-gcc $(which ${{ matrix.toolchain.host }}-gcc-posix)
- name: build
run: |
${{env.CCACHE_SETTINGS}}
make depends target=${{ matrix.toolchain.host }} -j2
- uses: actions/upload-artifact@v3
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin11' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
with:
name: ${{ matrix.toolchain.name }}
path: |
/home/runner/work/monero/monero/build/${{ matrix.toolchain.host }}/release/bin/monero-wallet-cli*
/home/runner/work/monero/monero/build/${{ matrix.toolchain.host }}/release/bin/monerod*
-49
View File
@@ -1,49 +0,0 @@
name: ci/gh-actions/gitian
on:
push:
tags:
- '*'
jobs:
build-gitian:
runs-on: ubuntu-20.04
strategy:
fail-fast: false
matrix:
operating-system:
- name: "Linux"
option: "l"
- name: "Windows"
option: "w"
- name: "Android"
option: "a"
- name: "FreeBSD"
option: "f"
- name: "macOS"
option: "m"
name: ${{ matrix.operating-system.name }}
steps:
- name: prepare
run: |
sudo apt update
curl -O https://raw.githubusercontent.com/monero-project/monero/${{ github.ref_name }}/contrib/gitian/gitian-build.py
chmod +x gitian-build.py
- name: setup
run: |
./gitian-build.py --setup --docker github-actions ${{ github.ref_name }}
- name: build
run: |
./gitian-build.py --docker --detach-sign --no-commit --build -j 3 -o ${{ matrix.operating-system.option }} github-actions ${{ github.ref_name }}
- name: post build
run: |
cd out/${{ github.ref_name }}
shasum -a256 *
echo \`\`\` >> $GITHUB_STEP_SUMMARY
shasum -a256 * >> $GITHUB_STEP_SUMMARY
echo \`\`\` >> $GITHUB_STEP_SUMMARY
- uses: actions/upload-artifact@v3
with:
name: ${{ matrix.operating-system.name }}
path: |
out/${{ github.ref_name }}/*
+3 -3
View File
@@ -1,6 +1,3 @@
[submodule "external/miniupnp"]
path = external/miniupnp
url = https://github.com/miniupnp/miniupnp
[submodule "external/rapidjson"]
path = external/rapidjson
url = https://github.com/Tencent/rapidjson
@@ -14,3 +11,6 @@
path = external/supercop
url = https://github.com/monero-project/supercop
branch = monero
[submodule "external/miniupnp"]
path = external/miniupnp
url = https://github.com/miniupnp/miniupnp
+2 -2
View File
@@ -46,7 +46,7 @@ endif()
cmake_minimum_required(VERSION 3.5)
message(STATUS "CMake version ${CMAKE_VERSION}")
project(monero)
project(salvium)
option (USE_CCACHE "Use ccache if a usable instance is found" ON)
if (USE_CCACHE)
@@ -1008,7 +1008,7 @@ else()
set(DEBUG_FLAGS "-g3")
# At least some CLANGs default to not enough for monero
# At least some CLANGs default to not enough for Salvium
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftemplate-depth=900")
if(NOT DEFINED USE_LTO_DEFAULT)
+1 -1
View File
@@ -1,4 +1,4 @@
# Portions Copyright (c) 2017-2022, The Monero Project
# Portions Copyright (c) 2017-2023, The Monero Project
# This file is based off of the https://code.google.com/archive/p/ios-cmake/
# It has been altered for Monero iOS development
#
+2 -2
View File
@@ -754,7 +754,7 @@ WARN_LOGFILE =
# spaces.
# Note: If this tag is empty the current directory is searched.
INPUT = .
INPUT = contrib/epee external/easylogging++ src
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -805,7 +805,7 @@ EXCLUDE_SYMLINKS = NO
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS = */build/* */contrib/depends/*
EXCLUDE_PATTERNS = */src/crypto/crypto_ops_builder/ref10*
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2014-2022, The Monero Project
Copyright (c) 2014-2023, The Monero Project
All rights reserved.
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2022, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -860
View File
@@ -1,860 +1 @@
# Monero
Copyright (c) 2014-2022 The Monero Project.
Portions Copyright (c) 2012-2013 The Cryptonote developers.
## Table of Contents
- [Development resources](#development-resources)
- [Vulnerability response](#vulnerability-response)
- [Research](#research)
- [Announcements](#announcements)
- [Translations](#translations)
- [Coverage](#coverage)
- [Introduction](#introduction)
- [About this project](#about-this-project)
- [Supporting the project](#supporting-the-project)
- [License](#license)
- [Contributing](#contributing)
- [Scheduled software upgrades](#scheduled-software-upgrades)
- [Release staging schedule and protocol](#release-staging-schedule-and-protocol)
- [Compiling Monero from source](#compiling-monero-from-source)
- [Dependencies](#dependencies)
- [Internationalization](#Internationalization)
- [Using Tor](#using-tor)
- [Pruning](#Pruning)
- [Debugging](#Debugging)
- [Known issues](#known-issues)
## Development resources
- Web: [getmonero.org](https://getmonero.org)
- Forum: [forum.getmonero.org](https://forum.getmonero.org)
- Mail: [dev@getmonero.org](mailto:dev@getmonero.org)
- GitHub: [https://github.com/monero-project/monero](https://github.com/monero-project/monero)
- IRC: [#monero-dev on Libera](https://web.libera.chat/#monero-dev)
- It is HIGHLY recommended that you join the #monero-dev IRC channel if you are developing software that uses Monero. Due to the nature of this open source software project, joining this channel and idling is the best way to stay updated on best practices and new developments in the Monero ecosystem. All you need to do is join the IRC channel and idle to stay updated with the latest in Monero development. If you do not, you risk wasting resources on developing integrations that are not compatible with the Monero network. The Monero core team and community continuously make efforts to communicate updates, developments, and documentation via other platforms but for the best information, you need to talk to other Monero developers, and they are on IRC. #monero-dev is about Monero development, not getting help about using Monero, or help about development of other software, including yours, unless it also pertains to Monero code itself. For these cases, checkout #monero.
## Vulnerability response
- Our [Vulnerability Response Process](https://github.com/monero-project/meta/blob/master/VULNERABILITY_RESPONSE_PROCESS.md) encourages responsible disclosure
- We are also available via [HackerOne](https://hackerone.com/monero)
## Research
The [Monero Research Lab](https://src.getmonero.org/resources/research-lab/) is an open forum where the community coordinates research into Monero cryptography, protocols, fungibility, analysis, and more. We welcome collaboration and contributions from outside researchers! Because not all Lab work and publications are distributed as traditional preprints or articles, they may be easy to miss if you are conducting literature reviews for your own Monero research. You are encouraged to get in touch with the Monero research community if you have questions, wish to collaborate, or would like guidance to help avoid unnecessarily duplicating earlier or known work.
The Monero research community is available on IRC in [#monero-research-lab on Libera](https://web.libera.chat/#monero-research-lab), which is also accessible via Matrix.
## Announcements
- You can subscribe to an [announcement listserv](https://lists.getmonero.org) to get critical announcements from the Monero core team. The announcement list can be very helpful for knowing when software updates are needed.
## Translations
The CLI wallet is available in different languages. If you want to help translate it, see our self-hosted localization platform, Weblate, on [translate.getmonero.org]( https://translate.getmonero.org/projects/monero/cli-wallet/). Every translation *must* be uploaded on the platform, pull requests directly editing the code in this repository will be closed. If you need help with Weblate, you can find a guide with screenshots [here](https://github.com/monero-ecosystem/monero-translations/blob/master/weblate.md).
 
If you need help/support/info about translations, contact the localization workgroup. You can find the complete list of contacts on the repository of the workgroup: [monero-translations](https://github.com/monero-ecosystem/monero-translations#contacts).
## Coverage
| Type | Status |
|-----------|--------|
| Coverity | [![Coverity Status](https://scan.coverity.com/projects/9657/badge.svg)](https://scan.coverity.com/projects/9657/)
| OSS Fuzz | [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/monero.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:monero)
| Coveralls | [![Coveralls Status](https://coveralls.io/repos/github/monero-project/monero/badge.svg?branch=master)](https://coveralls.io/github/monero-project/monero?branch=master)
| License | [![License](https://img.shields.io/badge/license-BSD3-blue.svg)](https://opensource.org/licenses/BSD-3-Clause)
## Introduction
Monero is a private, secure, untraceable, decentralised digital currency. You are your bank, you control your funds, and nobody can trace your transfers unless you allow them to do so.
**Privacy:** Monero uses a cryptographically sound system to allow you to send and receive funds without your transactions being easily revealed on the blockchain (the ledger of transactions that everyone has). This ensures that your purchases, receipts, and all transfers remain private by default.
**Security:** Using the power of a distributed peer-to-peer consensus network, every transaction on the network is cryptographically secured. Individual wallets have a 25-word mnemonic seed that is only displayed once and can be written down to backup the wallet. Wallet files should be encrypted with a strong passphrase to ensure they are useless if ever stolen.
**Untraceability:** By taking advantage of ring signatures, a special property of a certain type of cryptography, Monero is able to ensure that transactions are not only untraceable but have an optional measure of ambiguity that ensures that transactions cannot easily be tied back to an individual user or computer.
**Decentralization:** The utility of Monero depends on its decentralised peer-to-peer consensus network - anyone should be able to run the monero software, validate the integrity of the blockchain, and participate in all aspects of the monero network using consumer-grade commodity hardware. Decentralization of the monero network is maintained by software development that minimizes the costs of running the monero software and inhibits the proliferation of specialized, non-commodity hardware.
## About this project
This is the core implementation of Monero. It is open source and completely free to use without restrictions, except for those specified in the license agreement below. There are no restrictions on anyone creating an alternative implementation of Monero that uses the protocol and network in a compatible manner.
As with many development projects, the repository on GitHub is considered to be the "staging" area for the latest changes. Before changes are merged into that branch on the main repository, they are tested by individual developers in their own branches, submitted as a pull request, and then subsequently tested by contributors who focus on testing and code reviews. That having been said, the repository should be carefully considered before using it in a production environment, unless there is a patch in the repository for a particular show-stopping issue you are experiencing. It is generally a better idea to use a tagged release for stability.
**Anyone is welcome to contribute to Monero's codebase!** If you have a fix or code change, feel free to submit it as a pull request directly to the "master" branch. In cases where the change is relatively small or does not affect other parts of the codebase, it may be merged in immediately by any one of the collaborators. On the other hand, if the change is particularly large or complex, it is expected that it will be discussed at length either well in advance of the pull request being submitted, or even directly on the pull request.
## Supporting the project
Monero is a 100% community-sponsored endeavor. If you want to join our efforts, the easiest thing you can do is support the project financially. Both Monero and Bitcoin donations can be made to **donate.getmonero.org** if using a client that supports the [OpenAlias](https://openalias.org) standard. Alternatively, you can send XMR to the Monero donation address via the `donate` command (type `help` in the command-line wallet for details).
The Monero donation address is:
`888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H`
Viewkey:
`f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501`
Base address for restoring with address and viewkey:
`44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A`
The Bitcoin donation address is:
`1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H`
Core development funding and/or some supporting services are also graciously provided by [sponsors](https://www.getmonero.org/community/sponsorships/):
[<img width="150" src="https://www.getmonero.org/img/sponsors/tarilabs.png"/>](https://tarilabs.com/)
[<img width="150" src="https://www.getmonero.org/img/sponsors/globee.png"/>](https://globee.com/)
[<img width="150" src="https://www.getmonero.org/img/sponsors/symas.png"/>](https://symas.com/)
[<img width="150" src="https://www.getmonero.org/img/sponsors/forked_logo.png"/>](http://www.forked.net/)
[<img width="150" src="https://www.getmonero.org/img/sponsors/macstadium.png"/>](https://www.macstadium.com/)
There are also several mining pools that kindly donate a portion of their fees, [a list of them can be found on our Bitcointalk post](https://bitcointalk.org/index.php?topic=583449.0).
## License
See [LICENSE](LICENSE).
## Contributing
If you want to help out, see [CONTRIBUTING](docs/CONTRIBUTING.md) for a set of guidelines.
## Scheduled software upgrades
Monero uses a fixed-schedule software upgrade (hard fork) mechanism to implement new features. This means that users of Monero (end users and service providers) should run current versions and upgrade their software on a regular schedule. Software upgrades occur during the months of April and October. The required software for these upgrades will be available prior to the scheduled date. Please check the repository prior to this date for the proper Monero software version. Below is the historical schedule and the projected schedule for the next upgrade.
Dates are provided in the format YYYY-MM-DD.
| Software upgrade block height | Date | Fork version | Minimum Monero version | Recommended Monero version | Details |
| ------------------------------ | -----------| ----------------- | ---------------------- | -------------------------- | ---------------------------------------------------------------------------------- |
| 1009827 | 2016-03-22 | v2 | v0.9.4 | v0.9.4 | Allow only >= ringsize 3, blocktime = 120 seconds, fee-free blocksize 60 kb |
| 1141317 | 2016-09-21 | v3 | v0.9.4 | v0.10.0 | Splits coinbase into denominations |
| 1220516 | 2017-01-05 | v4 | v0.10.1 | v0.10.2.1 | Allow normal and RingCT transactions |
| 1288616 | 2017-04-15 | v5 | v0.10.3.0 | v0.10.3.1 | Adjusted minimum blocksize and fee algorithm |
| 1400000 | 2017-09-16 | v6 | v0.11.0.0 | v0.11.0.0 | Allow only RingCT transactions, allow only >= ringsize 5 |
| 1546000 | 2018-04-06 | v7 | v0.12.0.0 | v0.12.3.0 | Cryptonight variant 1, ringsize >= 7, sorted inputs
| 1685555 | 2018-10-18 | v8 | v0.13.0.0 | v0.13.0.4 | max transaction size at half the penalty free block size, bulletproofs enabled, cryptonight variant 2, fixed ringsize [11](https://youtu.be/KOO5S4vxi0o)
| 1686275 | 2018-10-19 | v9 | v0.13.0.0 | v0.13.0.4 | bulletproofs required
| 1788000 | 2019-03-09 | v10 | v0.14.0.0 | v0.14.1.2 | New PoW based on Cryptonight-R, new block weight algorithm, slightly more efficient RingCT format
| 1788720 | 2019-03-10 | v11 | v0.14.0.0 | v0.14.1.2 | forbid old RingCT transaction format
| 1978433 | 2019-11-30 | v12 | v0.15.0.0 | v0.16.0.0 | New PoW based on RandomX, only allow >= 2 outputs, change to the block median used to calculate penalty, v1 coinbases are forbidden, rct sigs in coinbase forbidden, 10 block lock time for incoming outputs
| 2210000 | 2020-10-17 | v13 | v0.17.0.0 | v0.17.3.2 | New CLSAG transaction format
| 2210720 | 2020-10-18 | v14 | v0.17.1.1 | v0.17.3.2 | forbid old MLSAG transaction format
| 2688888 | 2022-08-13 | v15 | v0.18.0.0 | v0.18.2.1 | ringsize = 16, bulletproofs+, view tags, adjusted dynamic block weight algorithm
| 2689608 | 2022-08-14 | v16 | v0.18.0.0 | v0.18.2.1 | forbid old v14 transaction format
| XXXXXXX | XXX-XX-XX | XXX | vX.XX.X.X | vX.XX.X.X | XXX |
X's indicate that these details have not been determined as of commit date.
\* indicates estimate as of commit date
## Release staging schedule and protocol
Approximately three months prior to a scheduled software upgrade, a branch from master will be created with the new release version tag. Pull requests that address bugs should then be made to both master and the new release branch. Pull requests that require extensive review and testing (generally, optimizations and new features) should *not* be made to the release branch.
## Compiling Monero from source
### Dependencies
The following table summarizes the tools and libraries required to build. A
few of the libraries are also included in this repository (marked as
"Vendored"). By default, the build uses the library installed on the system
and ignores the vendored sources. However, if no library is found installed on
the system, then the vendored source will be built and used. The vendored
sources are also used for statically-linked builds because distribution
packages often include only shared library binaries (`.so`) but not static
library archives (`.a`).
| Dep | Min. version | Vendored | Debian/Ubuntu pkg | Arch pkg | Void pkg | Fedora pkg | Optional | Purpose |
| ------------ | ------------- | -------- | -------------------- | ------------ | ------------------ | ------------------- | -------- | --------------- |
| GCC | 5 | NO | `build-essential` | `base-devel` | `base-devel` | `gcc` | NO | |
| CMake | 3.5 | NO | `cmake` | `cmake` | `cmake` | `cmake` | NO | |
| pkg-config | any | NO | `pkg-config` | `base-devel` | `base-devel` | `pkgconf` | NO | |
| Boost | 1.58 | NO | `libboost-all-dev` | `boost` | `boost-devel` | `boost-devel` | NO | C++ libraries |
| OpenSSL | basically any | NO | `libssl-dev` | `openssl` | `libressl-devel` | `openssl-devel` | NO | sha256 sum |
| libzmq | 4.2.0 | NO | `libzmq3-dev` | `zeromq` | `zeromq-devel` | `zeromq-devel` | NO | ZeroMQ library |
| OpenPGM | ? | NO | `libpgm-dev` | `libpgm` | | `openpgm-devel` | NO | For ZeroMQ |
| libnorm[2] | ? | NO | `libnorm-dev` | | | | YES | For ZeroMQ |
| libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | `unbound-devel` | NO | DNS resolver |
| libsodium | ? | NO | `libsodium-dev` | `libsodium` | `libsodium-devel` | `libsodium-devel` | NO | cryptography |
| libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | `libunwind-devel` | YES | Stack traces |
| liblzma | any | NO | `liblzma-dev` | `xz` | `liblzma-devel` | `xz-devel` | YES | For libunwind |
| libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | `readline-devel` | YES | Input editing |
| expat | 1.1 | NO | `libexpat1-dev` | `expat` | `expat-devel` | `expat-devel` | YES | XML parsing |
| GTest | 1.5 | YES | `libgtest-dev`[1] | `gtest` | `gtest-devel` | `gtest-devel` | YES | Test suite |
| ccache | any | NO | `ccache` | `ccache` | `ccache` | `ccache` | YES | Compil. cache |
| Doxygen | any | NO | `doxygen` | `doxygen` | `doxygen` | `doxygen` | YES | Documentation |
| Graphviz | any | NO | `graphviz` | `graphviz` | `graphviz` | `graphviz` | YES | Documentation |
| lrelease | ? | NO | `qttools5-dev-tools` | `qt5-tools` | `qt5-tools` | `qt5-linguist` | YES | Translations |
| libhidapi | ? | NO | `libhidapi-dev` | `hidapi` | `hidapi-devel` | `hidapi-devel` | YES | Hardware wallet |
| libusb | ? | NO | `libusb-1.0-0-dev` | `libusb` | `libusb-devel` | `libusbx-devel` | YES | Hardware wallet |
| libprotobuf | ? | NO | `libprotobuf-dev` | `protobuf` | `protobuf-devel` | `protobuf-devel` | YES | Hardware wallet |
| protoc | ? | NO | `protobuf-compiler` | `protobuf` | `protobuf` | `protobuf-compiler` | YES | Hardware wallet |
| libudev | ? | NO | `libudev-dev` | `systemd` | `eudev-libudev-devel` | `systemd-devel` | YES | Hardware wallet |
[1] On Debian/Ubuntu `libgtest-dev` only includes sources and headers. You must
build the library binary manually. This can be done with the following command `sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make`
then:
* on Debian:
`sudo mv libg* /usr/lib/`
* on Ubuntu:
`sudo mv lib/libg* /usr/lib/`
[2] libnorm-dev is needed if your zmq library was built with libnorm, and not needed otherwise
Install all dependencies at once on Debian/Ubuntu:
```
sudo apt update && sudo apt install build-essential cmake pkg-config libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libexpat1-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev python3 ccache doxygen graphviz
```
Install all dependencies at once on Arch:
```
sudo pacman -Syu --needed base-devel cmake boost openssl zeromq libpgm unbound libsodium libunwind xz readline expat gtest python3 ccache doxygen graphviz qt5-tools hidapi libusb protobuf systemd
```
Install all dependencies at once on Fedora:
```
sudo dnf install gcc gcc-c++ cmake pkgconf boost-devel openssl-devel zeromq-devel openpgm-devel unbound-devel libsodium-devel libunwind-devel xz-devel readline-devel expat-devel gtest-devel ccache doxygen graphviz qt5-linguist hidapi-devel libusbx-devel protobuf-devel protobuf-compiler systemd-devel
```
Install all dependencies at once on openSUSE:
```
sudo zypper ref && sudo zypper in cppzmq-devel libboost_chrono-devel libboost_date_time-devel libboost_filesystem-devel libboost_locale-devel libboost_program_options-devel libboost_regex-devel libboost_serialization-devel libboost_system-devel libboost_thread-devel libexpat-devel libminiupnpc-devel libsodium-devel libunwind-devel unbound-devel cmake doxygen ccache fdupes gcc-c++ libevent-devel libopenssl-devel pkgconf-pkg-config readline-devel xz-devel libqt5-qttools-devel patterns-devel-C-C++-devel_C_C++
```
Install all dependencies at once on macOS with the provided Brewfile:
```
brew update && brew bundle --file=contrib/brew/Brewfile
```
FreeBSD 12.1 one-liner required to build dependencies:
```
pkg install git gmake cmake pkgconf boost-libs libzmq4 libsodium unbound
```
### Cloning the repository
Clone recursively to pull-in needed submodule(s):
```
git clone --recursive https://github.com/monero-project/monero
```
If you already have a repo cloned, initialize and update:
```
cd monero && git submodule init && git submodule update
```
*Note*: If there are submodule differences between branches, you may need
to use `git submodule sync && git submodule update` after changing branches
to build successfully.
### Build instructions
Monero uses the CMake build system and a top-level [Makefile](Makefile) that
invokes cmake commands as needed.
#### On Linux and macOS
* Install the dependencies
* Change to the root of the source code directory, change to the most recent release branch, and build:
```bash
cd monero
git checkout release-v0.18
make
```
*Optional*: If your machine has several cores and enough memory, enable
parallel build by running `make -j<number of threads>` instead of `make`. For
this to be worthwhile, the machine should have one core and about 2GB of RAM
available per thread.
*Note*: The instructions above will compile the most stable release of the
Monero software. If you would like to use and test the most recent software,
use `git checkout master`. The master branch may contain updates that are
both unstable and incompatible with release software, though testing is always
encouraged.
* The resulting executables can be found in `build/release/bin`
* Add `PATH="$PATH:$HOME/monero/build/release/bin"` to `.profile`
* Run Monero with `monerod --detach`
* **Optional**: build and run the test suite to verify the binaries:
```bash
make release-test
```
*NOTE*: `core_tests` test may take a few hours to complete.
* **Optional**: to build binaries suitable for debugging:
```bash
make debug
```
* **Optional**: to build statically-linked binaries:
```bash
make release-static
```
Dependencies need to be built with -fPIC. Static libraries usually aren't, so you may have to build them yourself with -fPIC. Refer to their documentation for how to build them.
* **Optional**: build documentation in `doc/html` (omit `HAVE_DOT=YES` if `graphviz` is not installed):
```bash
HAVE_DOT=YES doxygen Doxyfile
```
* **Optional**: use ccache not to rebuild translation units, that haven't really changed. Monero's CMakeLists.txt file automatically handles it
```bash
sudo apt install ccache
```
#### On the Raspberry Pi
Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (2017-09-07 or later) from https://www.raspberrypi.org/downloads/raspbian/. If you are using Raspian Jessie, [please see note in the following section](#note-for-raspbian-jessie-users).
* `apt-get update && apt-get upgrade` to install all of the latest software
* Install the dependencies for Monero from the 'Debian' column in the table above.
* Increase the system swap size:
```bash
sudo /etc/init.d/dphys-swapfile stop
sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=2048
sudo /etc/init.d/dphys-swapfile start
```
* If using an external hard disk without an external power supply, ensure it gets enough power to avoid hardware issues when syncing, by adding the line "max_usb_current=1" to /boot/config.txt
* Clone Monero and checkout the most recent release version:
```bash
git clone https://github.com/monero-project/monero.git
cd monero
git checkout v0.18.2.1
```
* Build:
```bash
USE_SINGLE_BUILDDIR=1 make release
```
* Wait 4-6 hours
* The resulting executables can be found in `build/release/bin`
* Add `export PATH="$PATH:$HOME/monero/build/release/bin"` to `$HOME/.profile`
* Run `source $HOME/.profile`
* Run Monero with `monerod --detach`
* You may wish to reduce the size of the swap file after the build has finished, and delete the boost directory from your home directory
#### *Note for Raspbian Jessie users:*
If you are using the older Raspbian Jessie image, compiling Monero is a bit more complicated. The version of Boost available in the Debian Jessie repositories is too old to use with Monero, and thus you must compile a newer version yourself. The following explains the extra steps and has been tested on a Raspberry Pi 2 with a clean install of minimal Raspbian Jessie.
* As before, `apt-get update && apt-get upgrade` to install all of the latest software, and increase the system swap size
```bash
sudo /etc/init.d/dphys-swapfile stop
sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=2048
sudo /etc/init.d/dphys-swapfile start
```
* Then, install the dependencies for Monero except for `libunwind` and `libboost-all-dev`
* Install the latest version of boost (this may first require invoking `apt-get remove --purge libboost*-dev` to remove a previous version if you're not using a clean install):
```bash
cd
wget https://sourceforge.net/projects/boost/files/boost/1.72.0/boost_1_72_0.tar.bz2
tar xvfo boost_1_72_0.tar.bz2
cd boost_1_72_0
./bootstrap.sh
sudo ./b2
```
* Wait ~8 hours
```bash
sudo ./bjam cxxflags=-fPIC cflags=-fPIC -a install
```
* Wait ~4 hours
* From here, follow the [general Raspberry Pi instructions](#on-the-raspberry-pi) from the "Clone Monero and checkout most recent release version" step.
#### On Windows:
Binaries for Windows are built on Windows using the MinGW toolchain within
[MSYS2 environment](https://www.msys2.org). The MSYS2 environment emulates a
POSIX system. The toolchain runs within the environment and *cross-compiles*
binaries that can run outside of the environment as a regular Windows
application.
**Preparing the build environment**
* Download and install the [MSYS2 installer](https://www.msys2.org), either the 64-bit or the 32-bit package, depending on your system.
* Open the MSYS shell via the `MSYS2 Shell` shortcut
* Update packages using pacman:
```bash
pacman -Syu
```
* Exit the MSYS shell using Alt+F4
* Edit the properties for the `MSYS2 Shell` shortcut changing "msys2_shell.bat" to "msys2_shell.cmd -mingw64" for 64-bit builds or "msys2_shell.cmd -mingw32" for 32-bit builds
* Restart MSYS shell via modified shortcut and update packages again using pacman:
```bash
pacman -Syu
```
* Install dependencies:
To build for 64-bit Windows:
```bash
pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake mingw-w64-x86_64-boost mingw-w64-x86_64-openssl mingw-w64-x86_64-zeromq mingw-w64-x86_64-libsodium mingw-w64-x86_64-hidapi mingw-w64-x86_64-unbound
```
To build for 32-bit Windows:
```bash
pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake mingw-w64-i686-boost mingw-w64-i686-openssl mingw-w64-i686-zeromq mingw-w64-i686-libsodium mingw-w64-i686-hidapi mingw-w64-i686-unbound
```
* Open the MingW shell via `MinGW-w64-Win64 Shell` shortcut on 64-bit Windows
or `MinGW-w64-Win64 Shell` shortcut on 32-bit Windows. Note that if you are
running 64-bit Windows, you will have both 64-bit and 32-bit MinGW shells.
**Cloning**
* To git clone, run:
```bash
git clone --recursive https://github.com/monero-project/monero.git
```
**Building**
* Change to the cloned directory, run:
```bash
cd monero
```
* If you would like a specific [version/tag](https://github.com/monero-project/monero/tags), do a git checkout for that version. eg. 'v0.18.2.1'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.18.2.1
```
* If you are on a 64-bit system, run:
```bash
make release-static-win64
```
* If you are on a 32-bit system, run:
```bash
make release-static-win32
```
* The resulting executables can be found in `build/release/bin`
* **Optional**: to build Windows binaries suitable for debugging on a 64-bit system, run:
```bash
make debug-static-win64
```
* **Optional**: to build Windows binaries suitable for debugging on a 32-bit system, run:
```bash
make debug-static-win32
```
* The resulting executables can be found in `build/debug/bin`
### On FreeBSD:
The project can be built from scratch by following instructions for Linux above(but use `gmake` instead of `make`).
If you are running Monero in a jail, you need to add `sysvsem="new"` to your jail configuration, otherwise lmdb will throw the error message: `Failed to open lmdb environment: Function not implemented`.
Monero is also available as a port or package as `monero-cli`.
### On OpenBSD:
You will need to add a few packages to your system. `pkg_add cmake gmake zeromq libiconv boost`.
The `doxygen` and `graphviz` packages are optional and require the xbase set.
Running the test suite also requires `py-requests` package.
Build monero: `env DEVELOPER_LOCAL_TOOLS=1 BOOST_ROOT=/usr/local gmake release-static`
Note: you may encounter the following error when compiling the latest version of Monero as a normal user:
```
LLVM ERROR: out of memory
c++: error: unable to execute command: Abort trap (core dumped)
```
Then you need to increase the data ulimit size to 2GB and try again: `ulimit -d 2000000`
### On NetBSD:
Check that the dependencies are present: `pkg_info -c libexecinfo boost-headers boost-libs protobuf readline libusb1 zeromq git-base pkgconf gmake cmake | more`, and install any that are reported missing, using `pkg_add` or from your pkgsrc tree. Readline is optional but worth having.
Third-party dependencies are usually under `/usr/pkg/`, but if you have a custom setup, adjust the "/usr/pkg" (below) accordingly.
Clone the monero repository recursively and checkout the most recent release as described above. Then build monero: `gmake BOOST_ROOT=/usr/pkg LDFLAGS="-Wl,-R/usr/pkg/lib" release`. The resulting executables can be found in `build/NetBSD/[Release version]/Release/bin/`.
### On Solaris:
The default Solaris linker can't be used, you have to install GNU ld, then run cmake manually with the path to your copy of GNU ld:
```bash
mkdir -p build/release
cd build/release
cmake -DCMAKE_LINKER=/path/to/ld -D CMAKE_BUILD_TYPE=Release ../..
cd ../..
```
Then you can run make as usual.
### Building portable statically linked binaries
By default, in either dynamically or statically linked builds, binaries target the specific host processor on which the build happens and are not portable to other processors. Portable binaries can be built using the following targets:
* ```make release-static-linux-x86_64``` builds binaries on Linux on x86_64 portable across POSIX systems on x86_64 processors
* ```make release-static-linux-i686``` builds binaries on Linux on x86_64 or i686 portable across POSIX systems on i686 processors
* ```make release-static-linux-armv8``` builds binaries on Linux portable across POSIX systems on armv8 processors
* ```make release-static-linux-armv7``` builds binaries on Linux portable across POSIX systems on armv7 processors
* ```make release-static-linux-armv6``` builds binaries on Linux portable across POSIX systems on armv6 processors
* ```make release-static-win64``` builds binaries on 64-bit Windows portable across 64-bit Windows systems
* ```make release-static-win32``` builds binaries on 64-bit or 32-bit Windows portable across 32-bit Windows systems
### Cross Compiling
You can also cross-compile static binaries on Linux for Windows and macOS with the `depends` system.
* ```make depends target=x86_64-linux-gnu``` for 64-bit linux binaries.
* ```make depends target=x86_64-w64-mingw32``` for 64-bit windows binaries.
* Requires: `python3 g++-mingw-w64-x86-64 wine1.6 bc`
* ```make depends target=x86_64-apple-darwin11``` for macOS binaries.
* Requires: `cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev`
* ```make depends target=i686-linux-gnu``` for 32-bit linux binaries.
* Requires: `g++-multilib bc`
* ```make depends target=i686-w64-mingw32``` for 32-bit windows binaries.
* Requires: `python3 g++-mingw-w64-i686`
* ```make depends target=arm-linux-gnueabihf``` for armv7 binaries.
* Requires: `g++-arm-linux-gnueabihf`
* ```make depends target=aarch64-linux-gnu``` for armv8 binaries.
* Requires: `g++-aarch64-linux-gnu`
* ```make depends target=riscv64-linux-gnu``` for RISC V 64 bit binaries.
* Requires: `g++-riscv64-linux-gnu`
* ```make depends target=x86_64-unknown-freebsd``` for freebsd binaries.
* Requires: `clang-8`
* ```make depends target=arm-linux-android``` for 32bit android binaries
* ```make depends target=aarch64-linux-android``` for 64bit android binaries
The required packages are the names for each toolchain on apt. Depending on your distro, they may have different names. The `depends` system has been tested on Ubuntu 18.04 and 20.04.
Using `depends` might also be easier to compile Monero on Windows than using MSYS. Activate Windows Subsystem for Linux (WSL) with a distro (for example Ubuntu), install the apt build-essentials and follow the `depends` steps as depicted above.
The produced binaries still link libc dynamically. If the binary is compiled on a current distribution, it might not run on an older distribution with an older installation of libc. Passing `-DBACKCOMPAT=ON` to cmake will make sure that the binary will run on systems having at least libc version 2.17.
## Installing Monero from a package
**DISCLAIMER: These packages are not part of this repository or maintained by this project's contributors, and as such, do not go through the same review process to ensure their trustworthiness and security.**
Packages are available for
* Debian Buster
See the [instructions in the whonix/monero-gui repository](https://gitlab.com/whonix/monero-gui#how-to-install-monero-using-apt-get)
* Debian Bullseye and Sid
```bash
sudo apt install monero
```
More info and versions in the [Debian package tracker](https://tracker.debian.org/pkg/monero).
* Arch Linux [(via Community packages)](https://www.archlinux.org/packages/community/x86_64/monero/):
```bash
sudo pacman -S monero
```
* Void Linux:
```bash
xbps-install -S monero
```
* GuixSD
```bash
guix package -i monero
```
* Gentoo [Monero overlay](https://github.com/gentoo-monero/gentoo-monero)
```bash
emerge --noreplace eselect-repository
eselect repository enable monero
emaint sync -r monero
echo '*/*::monero ~amd64' >> /etc/portage/package.accept_keywords
emerge net-p2p/monero
```
* macOS [(homebrew)](https://brew.sh/)
```bash
brew install monero
```
* Docker
```bash
# Build using all available cores
docker build -t monero .
# or build using a specific number of cores (reduce RAM requirement)
docker build --build-arg NPROC=1 -t monero .
# either run in foreground
docker run -it -v /monero/chain:/home/monero/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
# or in background
docker run -it -d -v /monero/chain:/home/monero/.bitmonero -v /monero/wallet:/wallet -p 18080:18080 monero
```
* The build needs 3 GB space.
* Wait one hour or more
Packaging for your favorite distribution would be a welcome contribution!
## Running monerod
The build places the binary in `bin/` sub-directory within the build directory
from which cmake was invoked (repository root by default). To run in the
foreground:
```bash
./bin/monerod
```
To list all available options, run `./bin/monerod --help`. Options can be
specified either on the command line or in a configuration file passed by the
`--config-file` argument. To specify an option in the configuration file, add
a line with the syntax `argumentname=value`, where `argumentname` is the name
of the argument without the leading dashes, for example, `log-level=1`.
To run in background:
```bash
./bin/monerod --log-file monerod.log --detach
```
To run as a systemd service, copy
[monerod.service](utils/systemd/monerod.service) to `/etc/systemd/system/` and
[monerod.conf](utils/conf/monerod.conf) to `/etc/`. The [example
service](utils/systemd/monerod.service) assumes that the user `monero` exists
and its home is the data directory specified in the [example
config](utils/conf/monerod.conf).
If you're on Mac, you may need to add the `--max-concurrency 1` option to
monero-wallet-cli, and possibly monerod, if you get crashes refreshing.
## Internationalization
See [README.i18n.md](docs/README.i18n.md).
## Using Tor
> There is a new, still experimental, [integration with Tor](docs/ANONYMITY_NETWORKS.md). The
> feature allows connecting over IPv4 and Tor simultaneously - IPv4 is used for
> relaying blocks and relaying transactions received by peers whereas Tor is
> used solely for relaying transactions received over local RPC. This provides
> privacy and better protection against surrounding node (sybil) attacks.
While Monero isn't made to integrate with Tor, it can be used wrapped with torsocks, by
setting the following configuration parameters and environment variables:
* `--p2p-bind-ip 127.0.0.1` on the command line or `p2p-bind-ip=127.0.0.1` in
monerod.conf to disable listening for connections on external interfaces.
* `--no-igd` on the command line or `no-igd=1` in monerod.conf to disable IGD
(UPnP port forwarding negotiation), which is pointless with Tor.
* `DNS_PUBLIC=tcp` or `DNS_PUBLIC=tcp://x.x.x.x` where x.x.x.x is the IP of the
desired DNS server, for DNS requests to go over TCP, so that they are routed
through Tor. When IP is not specified, monerod uses the default list of
servers defined in [src/common/dns_utils.cpp](src/common/dns_utils.cpp).
* `TORSOCKS_ALLOW_INBOUND=1` to tell torsocks to allow monerod to bind to interfaces
to accept connections from the wallet. On some Linux systems, torsocks
allows binding to localhost by default, so setting this variable is only
necessary to allow binding to local LAN/VPN interfaces to allow wallets to
connect from remote hosts. On other systems, it may be needed for local wallets
as well.
* Do NOT pass `--detach` when running through torsocks with systemd, (see
[utils/systemd/monerod.service](utils/systemd/monerod.service) for details).
* If you use the wallet with a Tor daemon via the loopback IP (eg, 127.0.0.1:9050),
then use `--untrusted-daemon` unless it is your own hidden service.
Example command line to start monerod through Tor:
```bash
DNS_PUBLIC=tcp torsocks monerod --p2p-bind-ip 127.0.0.1 --no-igd
```
A helper script is in contrib/tor/monero-over-tor.sh. It assumes Tor is installed
already, and runs Tor and Monero with the right configuration.
### Using Tor on Tails
TAILS ships with a very restrictive set of firewall rules. Therefore, you need
to add a rule to allow this connection too, in addition to telling torsocks to
allow inbound connections. Full example:
```bash
sudo iptables -I OUTPUT 2 -p tcp -d 127.0.0.1 -m tcp --dport 18081 -j ACCEPT
DNS_PUBLIC=tcp torsocks ./monerod --p2p-bind-ip 127.0.0.1 --no-igd --rpc-bind-ip 127.0.0.1 \
--data-dir /home/amnesia/Persistent/your/directory/to/the/blockchain
```
## Pruning
As of April 2022, the full Monero blockchain file is about 130 GB. One can store a pruned blockchain, which is about 45 GB.
A pruned blockchain can only serve part of the historical chain data to other peers, but is otherwise identical in
functionality to the full blockchain.
To use a pruned blockchain, it is best to start the initial sync with `--prune-blockchain`. However, it is also possible
to prune an existing blockchain using the `monero-blockchain-prune` tool or using the `--prune-blockchain` `monerod` option
with an existing chain. If an existing chain exists, pruning will temporarily require disk space to store both the full
and pruned blockchains.
For more detailed information see the ['Pruning' entry in the Moneropedia](https://www.getmonero.org/resources/moneropedia/pruning.html)
## Debugging
This section contains general instructions for debugging failed installs or problems encountered with Monero. First, ensure you are running the latest version built from the GitHub repo.
### Obtaining stack traces and core dumps on Unix systems
We generally use the tool `gdb` (GNU debugger) to provide stack trace functionality, and `ulimit` to provide core dumps in builds which crash or segfault.
* To use `gdb` in order to obtain a stack trace for a build that has stalled:
Run the build.
Once it stalls, enter the following command:
```bash
gdb /path/to/monerod `pidof monerod`
```
Type `thread apply all bt` within gdb in order to obtain the stack trace
* If however the core dumps or segfaults:
Enter `ulimit -c unlimited` on the command line to enable unlimited filesizes for core dumps
Enter `echo core | sudo tee /proc/sys/kernel/core_pattern` to stop cores from being hijacked by other tools
Run the build.
When it terminates with an output along the lines of "Segmentation fault (core dumped)", there should be a core dump file in the same directory as monerod. It may be named just `core`, or `core.xxxx` with numbers appended.
You can now analyse this core dump with `gdb` as follows:
```bash
gdb /path/to/monerod /path/to/dumpfile`
```
Print the stack trace with `bt`
* If a program crashed and cores are managed by systemd, the following can also get a stack trace for that crash:
```bash
coredumpctl -1 gdb
```
#### To run Monero within gdb:
Type `gdb /path/to/monerod`
Pass command-line options with `--args` followed by the relevant arguments
Type `run` to run monerod
### Analysing memory corruption
There are two tools available:
#### ASAN
Configure Monero with the -D SANITIZE=ON cmake flag, eg:
```bash
cd build/debug && cmake -D SANITIZE=ON -D CMAKE_BUILD_TYPE=Debug ../..
```
You can then run the monero tools normally. Performance will typically halve.
#### valgrind
Install valgrind and run as `valgrind /path/to/monerod`. It will be very slow.
### LMDB
Instructions for debugging suspected blockchain corruption as per @HYC
There is an `mdb_stat` command in the LMDB source that can print statistics about the database but it's not routinely built. This can be built with the following command:
```bash
cd ~/monero/external/db_drivers/liblmdb && make
```
The output of `mdb_stat -ea <path to blockchain dir>` will indicate inconsistencies in the blocks, block_heights and block_info table.
The output of `mdb_dump -s blocks <path to blockchain dir>` and `mdb_dump -s block_info <path to blockchain dir>` is useful for indicating whether blocks and block_info contain the same keys.
These records are dumped as hex data, where the first line is the key and the second line is the data.
# Known Issues
## Protocols
### Socket-based
Because of the nature of the socket-based protocols that drive monero, certain protocol weaknesses are somewhat unavoidable at this time. While these weaknesses can theoretically be fully mitigated, the effort required (the means) may not justify the ends. As such, please consider taking the following precautions if you are a monero node operator:
- Run `monerod` on a "secured" machine. If operational security is not your forte, at a very minimum, have a dedicated a computer running `monerod` and **do not** browse the web, use email clients, or use any other potentially harmful apps on your `monerod` machine. **Do not click links or load URL/MUA content on the same machine**. Doing so may potentially exploit weaknesses in commands which accept "localhost" and "127.0.0.1".
- If you plan on hosting a public "remote" node, start `monerod` with `--restricted-rpc`. This is a must.
### Blockchain-based
Certain blockchain "features" can be considered "bugs" if misused correctly. Consequently, please consider the following:
- When receiving monero, be aware that it may be locked for an arbitrary time if the sender elected to, preventing you from spending that monero until the lock time expires. You may want to hold off acting upon such a transaction until the unlock time lapses. To get a sense of that time, you can consider the remaining blocktime until unlock as seen in the `show_transfers` command.
# Welcome to Salvium
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2022, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2022, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2022, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2022, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2022, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2022, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2022, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2022, The Monero Project
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2022, The Monero Project
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2022, The Monero Project
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2022, The Monero Project
// Copyright (c) 2014-2023, The Monero Project
//
// All rights reserved.
//
+1 -1
View File
@@ -145,7 +145,7 @@ $(1)_build_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_stage_env+=PATH="$(build_prefix)/bin:$(PATH)"
$(1)_autoconf=./configure --host=$($($(1)_type)_host) --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)"
ifneq ($(1),libusb)
ifeq ($(filter $(1),libusb unbound),)
$(1)_autoconf += --disable-dependency-tracking
endif
ifneq ($($(1)_nm),)
+6 -6
View File
@@ -1,12 +1,12 @@
package=expat
$(package)_version=2.4.1
$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_2_4_1
$(package)_version=2.6.0
$(package)_download_path=https://github.com/libexpat/libexpat/releases/download/R_$(subst .,_,$($(package)_version))/
$(package)_file_name=$(package)-$($(package)_version).tar.bz2
$(package)_sha256_hash=2f9b6a580b94577b150a7d5617ad4643a4301a6616ff459307df3e225bcfbf40
$(package)_sha256_hash=ff60e6a6b6ce570ae012dc7b73169c7fdf4b6bf08c12ed0ec6f55736b78d85ba
define $(package)_set_vars
$(package)_config_opts=--enable-static
$(package)_config_opts=--disable-shared
$(package)_config_opts=--disable-shared --without-docbook --without-tests --without-examples
$(package)_config_opts+=--enable-option-checking --without-xmlwf --with-pic
$(package)_config_opts+=--prefix=$(host_prefix)
endef
@@ -23,6 +23,6 @@ define $(package)_stage_cmds
endef
define $(package)_postprocess_cmds
rm lib/*.la
rm -rf share lib/cmake lib/*.la
endef
+7 -8
View File
@@ -1,20 +1,19 @@
package=openssl
$(package)_version=1.1.1t
$(package)_version=3.0.13
$(package)_download_path=https://www.openssl.org/source
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=8dee9b24bdb1dcbf0c3d1e9b02fb8f6bf22165e807f45adeb7c9677536859d3b
$(package)_sha256_hash=88525753f79d3bec27d2fa7c66aa0b92b3aa9498dafd93d7cfa4b3780cdae313
define $(package)_set_vars
$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)"
$(package)_config_env_android=ANDROID_NDK_HOME="$(host_prefix)/native" PATH="$(host_prefix)/native/bin" CC=clang AR=ar RANLIB=ranlib
$(package)_build_env_android=ANDROID_NDK_HOME="$(host_prefix)/native"
$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl
$(package)_config_env_android=ANDROID_NDK_ROOT="$(host_prefix)/native" PATH="$(host_prefix)/native/bin" CC=clang AR=ar RANLIB=ranlib
$(package)_build_env_android=ANDROID_NDK_ROOT="$(host_prefix)/native"
$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl --libdir=$(host_prefix)/lib
$(package)_config_opts+=no-capieng
$(package)_config_opts+=no-dso
$(package)_config_opts+=no-dtls1
$(package)_config_opts+=no-ec_nistp_64_gcc_128
$(package)_config_opts+=no-gost
$(package)_config_opts+=no-heartbeats
$(package)_config_opts+=no-md2
$(package)_config_opts+=no-rc5
$(package)_config_opts+=no-rdrand
@@ -22,8 +21,8 @@ $(package)_config_opts+=no-rfc3779
$(package)_config_opts+=no-sctp
$(package)_config_opts+=no-shared
$(package)_config_opts+=no-ssl-trace
$(package)_config_opts+=no-ssl2
$(package)_config_opts+=no-ssl3
$(package)_config_opts+=no-tests
$(package)_config_opts+=no-unit-test
$(package)_config_opts+=no-weak-ssl-ciphers
$(package)_config_opts+=no-zlib
@@ -49,7 +48,7 @@ $(package)_config_opts_x86_64_freebsd=BSD-x86_64
endef
define $(package)_preprocess_cmds
sed -i.old 's|"engines", "apps", "test", "util", "tools", "fuzz"|"engines", "tools"|' Configure
sed -i.old 's|crypto ssl apps util tools fuzz providers doc|crypto ssl util tools providers|' build.info
endef
define $(package)_config_cmds
+7 -6
View File
@@ -1,17 +1,21 @@
package=unbound
$(package)_version=1.15.0
$(package)_version=1.19.1
$(package)_download_path=https://www.nlnetlabs.nl/downloads/$(package)/
$(package)_file_name=$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=a480dc6c8937447b98d161fe911ffc76cfaffa2da18788781314e81339f1126f
$(package)_sha256_hash=bc1d576f3dd846a0739adc41ffaa702404c6767d2b6082deb9f2f97cbb24a3a9
$(package)_dependencies=openssl expat
$(package)_patches=disable-glibc-reallocarray.patch
define $(package)_set_vars
$(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) --with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads --with-libunbound-only
$(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+=--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
define $(package)_preprocess_cmds
@@ -30,6 +34,3 @@ endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
define $(package)_postprocess_cmds
endef
+5 -2
View File
@@ -144,8 +144,11 @@ elseif(ARCHITECTURE STREQUAL "aarch64")
endif()
if(ARCHITECTURE STREQUAL "riscv64")
set(NO_AES ON)
set(ARCH "rv64imafdc")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(BUILD_TAG "linux-riscv64")
endif()
set(ARCH_ID "riscv64")
set(ARCH "rv64gc")
endif()
if(ARCHITECTURE STREQUAL "i686")
+1
View File
@@ -29,6 +29,7 @@
#include <string>
#include <ctime>
#include <cstdint>
namespace epee
{
@@ -583,11 +583,8 @@ namespace net_utils
break;
}
}
else if (ec.value())
terminate();
else {
cancel_timer();
on_interrupted();
terminate();
}
};
m_strand.post(
+10
View File
@@ -147,6 +147,16 @@ namespace epee
return {reinterpret_cast<const std::uint8_t*>(src.data()), src.size_bytes()};
}
//! \return `span<std::uint8_t>` from a STL compatible `src`.
template<typename T>
constexpr span<std::uint8_t> to_mut_byte_span(T& src)
{
using value_type = typename T::value_type;
static_assert(!std::is_empty<value_type>(), "empty value types will not work -> sizeof == 1");
static_assert(!has_padding<value_type>(), "source value type may have padding");
return {reinterpret_cast<std::uint8_t*>(src.data()), src.size() * sizeof(value_type)};
}
//! \return `span<const std::uint8_t>` which represents the bytes at `&src`.
template<typename T>
span<const std::uint8_t> as_byte_span(const T& src) noexcept
@@ -30,6 +30,7 @@
#include <boost/utility/string_ref_fwd.hpp>
#include <string>
#include <cstdint>
namespace epee
{
@@ -33,6 +33,9 @@
#include "portable_storage_base.h"
#include "portable_storage_bin_utils.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "serialization"
#ifdef EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
#define EPEE_PORTABLE_STORAGE_RECURSION_LIMIT_INTERNAL EPEE_PORTABLE_STORAGE_RECURSION_LIMIT
#else
@@ -227,6 +230,7 @@ namespace epee
case SERIALIZE_TYPE_ARRAY: return read_ae<array_entry>();
default:
CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << type);
return epee::serialization::storage_entry(0);
}
}
@@ -318,6 +322,7 @@ namespace epee
case SERIALIZE_TYPE_ARRAY: return read_se<array_entry>();
default:
CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << ent_type);
return epee::serialization::storage_entry(0);
}
}
inline
@@ -31,6 +31,9 @@
#include "parserse_base_utils.h"
#include "file_io_utils.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "serialization"
#define EPEE_JSON_RECURSION_LIMIT_INTERNAL 100
namespace epee
@@ -36,6 +36,7 @@
#include "warnings.h"
#include "misc_log_ex.h"
#include <boost/numeric/conversion/bounds.hpp>
#include <boost/lexical_cast.hpp>
#include <typeinfo>
#include <iomanip>
+13
View File
@@ -338,11 +338,21 @@ bool is_stdout_a_tty()
return is_a_tty.load(std::memory_order_relaxed);
}
static bool is_nocolor()
{
static const char *no_color_var = getenv("NO_COLOR");
static const bool no_color = no_color_var && *no_color_var; // apparently, NO_COLOR=0 means no color too (as per no-color.org)
return no_color;
}
void set_console_color(int color, bool bright)
{
if (!is_stdout_a_tty())
return;
if (is_nocolor())
return;
switch(color)
{
case console_color_default:
@@ -461,6 +471,9 @@ void reset_console_color() {
if (!is_stdout_a_tty())
return;
if (is_nocolor())
return;
#ifdef WIN32
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(h_stdout, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+8 -5
View File
@@ -496,6 +496,13 @@ void ssl_options_t::configure(
const std::string& host) const
{
socket.next_layer().set_option(boost::asio::ip::tcp::no_delay(true));
{
// in case server is doing "virtual" domains, set hostname
SSL* const ssl_ctx = socket.native_handle();
if (type == boost::asio::ssl::stream_base::client && !host.empty() && ssl_ctx)
SSL_set_tlsext_host_name(ssl_ctx, host.c_str());
}
/* Using system-wide CA store for client verification is funky - there is
no expected hostname for server to verify against. If server doesn't have
@@ -513,11 +520,7 @@ void ssl_options_t::configure(
{
socket.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert);
// in case server is doing "virtual" domains, set hostname
SSL* const ssl_ctx = socket.native_handle();
if (type == boost::asio::ssl::stream_base::client && !host.empty() && ssl_ctx)
SSL_set_tlsext_host_name(ssl_ctx, host.c_str());
socket.set_verify_callback([&](const bool preverified, boost::asio::ssl::verify_context &ctx)
{
// preverified means it passed system or user CA check. System CA is never loaded
+4
View File
@@ -238,6 +238,10 @@ static char** attempted_completion(const char* text, int start, int end)
static void install_line_handler()
{
#if RL_READLINE_VERSION >= 0x0801
rl_variable_bind("enable-bracketed-paste", "off");
#endif
rl_attempted_completion_function = attempted_completion;
rl_callback_handler_install("", handle_line);
stifle_history(500);
+1 -1
View File
@@ -57,7 +57,7 @@ The dockrun.sh script will do everything to build the binaries. Just specify the
version to build as its only argument, e.g.
```bash
VERSION=v0.18.2.1
VERSION=v0.18.3.3
./dockrun.sh $VERSION
```
+1 -1
View File
@@ -133,7 +133,7 @@ Common setup part:
su - gitianuser
GH_USER=YOUR_GITHUB_USER_NAME
VERSION=v0.18.2.1
VERSION=v0.18.3.3
```
Where `GH_USER` is your GitHub user name and `VERSION` is the version tag you want to build.
+9 -2
View File
@@ -21,6 +21,7 @@ packages:
- "g++-7-arm-linux-gnueabihf"
- "gcc-arm-linux-gnueabihf"
- "g++-arm-linux-gnueabihf"
- "g++-riscv64-linux-gnu"
- "g++-7-multilib"
- "gcc-7-multilib"
- "binutils-arm-linux-gnueabihf"
@@ -43,7 +44,7 @@ files: []
script: |
WRAP_DIR=$HOME/wrapped
HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu i686-linux-gnu"
HOSTS="x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu i686-linux-gnu riscv64-linux-gnu"
FAKETIME_HOST_PROGS=""
FAKETIME_PROGS="date"
HOST_CFLAGS="-O2 -g"
@@ -159,7 +160,13 @@ script: |
fi
export C_INCLUDE_PATH="$EXTRA_INCLUDES"
export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES"
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=ON -DCMAKE_SKIP_RPATH=ON
# glibc only added riscv support in 2.27, disable backwards compatibility
if [ "$i" == "riscv64-linux-gnu" ]; then
BACKCOMPAT_OPTION=OFF
else
BACKCOMPAT_OPTION=ON
fi
cmake .. -DCMAKE_TOOLCHAIN_FILE=${BASEPREFIX}/${i}/share/toolchain.cmake -DBACKCOMPAT=${BACKCOMPAT_OPTION} -DCMAKE_SKIP_RPATH=ON
make ${MAKEOPTS}
chmod 755 bin/*
cp ../LICENSE ../README.md ../docs/ANONYMITY_NETWORKS.md bin
+1 -1
View File
@@ -56,7 +56,7 @@ the previous paragraph is here.
## License
Copyright (c) 2009-2015 Pieter Hintjens.
Copyright (c) 2017-2022, The Monero Project
Copyright (c) 2017-2023, The Monero Project
This Specification is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
+45 -3
View File
@@ -158,7 +158,7 @@ that most will be familiar with):
```json
{
"short_quote": "Give me liberty or give me death!",
"short_quote": "Give me liberty or give me death",
"long_quote": "Monero is more than just a technology. It's also what the technology stands for.",
"signed_32bit_int": 20140418,
"array_of_bools": [true, false, true, true],
@@ -169,9 +169,51 @@ that most will be familiar with):
}
```
This would translate to:
This object would translate into the following bytes when serialized into epee portable storage format. The bytes are represented in hex, with comments and whitespace added for readability.
![Epee binary storage format example](/docs/images/storage_binary_example.png)
```
01 11 01 01 01 01 02 01 // Signature
01 // Version
14 // Varint number of section entries (5)
0b // Length of next section key (11)
73 68 6f 72 74 5f 71 75 6f 74 65 // Section key ("short_quote")
0a // Type code (STRING)
80 // Varint length of string (32)
47 69 76 65 20 6d 65 20 6c 69 62 65 72 74 79 20 // STRING value ("Give me liberty ")
6f 72 20 67 69 76 65 20 6d 65 20 64 65 61 74 68 // STRING value cont. ("or give me death")
0a // Length of next section key (10)
6c 6f 6e 67 5f 71 75 6f 74 65 // Section key ("long_quote")
0a // Type code (STRING)
41 01 // Varint length of string (80). Note it's 2 bytes
4d 6f 6e 65 72 6f 20 69 73 20 6d 6f 72 65 20 74 // STRING value ("Monero is more t")
68 61 6e 20 6a 75 73 74 20 61 20 74 65 63 68 6e // STRING value cont. ("han just a techn")
6f 6c 6f 67 79 2e 20 49 74 27 73 20 61 6c 73 6f // STRING value cont. ("ology. It's also")
20 77 68 61 74 20 74 68 65 20 74 65 63 68 6e 6f // STRING value cont. (" what the techno")
6c 6f 67 79 20 73 74 61 6e 64 73 20 66 6f 72 2e // STRING value cont. ("logy stands for.")
10 // Length of next section key (16)
73 69 67 6e 65 64 5f 33 32 62 69 74 5f 69 6e 74 // Section key ("signed_32bit_int")
02 // type code (INT32)
82 51 33 01 // INT32 value (20140418)
0e // Length of next section key (14)
61 72 72 61 79 5f 6f 66 5f 62 6f 6f 6c 73 // Section key ("array_of_bools")
8b // Type code (BOOL | FLAG_ARRAY)
10 // Varint number of array elements (4)
01 00 01 01 // Array BOOL values [true, false, true, true]
0e // Length of next section key (14)
6e 65 73 74 65 64 5f 73 65 63 74 69 6f 6e // Section key ("nested_section")
0c // Type code (OBJECT)
08 // Varint number of inner section entries (2)
06 // Length of first inner section key (6)
64 6f 75 62 6c 65 // Section key ("double")
09 // Type code (DOUBLE)
9a 99 99 99 99 99 1b c0 // DOUBLE value (-6.9)
12 // Length of second inner section key (18)
75 6e 73 69 67 6e 65 64 5f 36 34 62 69 74 5f 69 // Section key ("unsigned_64bit_i")
6e 74 // Section key cont ("nt")
05 // Type code (UINT64)
c7 71 ac b5 af 98 32 9a // UINT64 value (11111111111111111111)
```
## Monero specifics
+23 -11
View File
@@ -1,15 +1,20 @@
# Monero hard-fork release check-list
- [ ] Security audit
- [ ] Code audit
- [ ] Ledger integration
- [ ] Implemented in Monero codebase (if needed)
- [ ] Ledger app integration coded by Ledger
- [ ] Ledger notified
- [ ] Pull request made against Monero codebase (if needed)
- [ ] Pull request merged into Monero codebase (if needed)
- [ ] Ledger app integration coded
- [ ] Ledger Monero app update available
- [ ] Trezor integration
- [ ] Implemented in Monero codebase (if needed)
- [ ] Trezor app integration coded by Trezor
- [ ] Trezor firmware update available (if needed)
- [ ] Trezor notified
- [ ] Pull request made against Monero codebase (if needed)
- [ ] Pull request merged into Monero codebase (if needed)
- [ ] Trezor firmware update coded
- [ ] Trezor firmware update available
- [ ] Fork height set
- [ ] Monero-announce mailer notice
- [ ] Twitter announcement
- [ ] Reddit announcement
- [ ] Getmonero.org announcement
@@ -26,13 +31,15 @@
- [ ] Edge Wallet
- [ ] Exodus
- [ ] XMRWallet
- [ ] Feather Wallet
- [ ] Notify exchanges
- [ ] https://web.getmonero.org/community/merchants/#exchanges
- [ ] https://www.getmonero.org/community/merchants/#exchanges
- [ ] Notify 3rd party payment processors
- [ ] https://web.getmonero.org/community/merchants/#payment-gateways
- [ ] https://www.getmonero.org/community/merchants/#payment-gateways
- [ ] BTCPayServer
- [ ] Notify mining pools
- [ ] https://miningpoolstats.stream/monero
- [ ] Release tagged
- [ ] Release branch created
- [ ] Update src/version.cpp.in with new version AND new name (if necessary)
- [ ] Update Gitian YML files in contrib/gitian/ to the new version number
- [ ] Update README.md with new fork table entry (or at least update the Recommended Monero version)
@@ -46,16 +53,21 @@
- [ ] Trezor
- [ ] Release-specific testing
- [ ] RPC testing/update RPC documentation
- [ ] Stagenet forked
- [ ] Stagenet testing/verification
- [ ] Ledger
- [ ] Trezor
- [ ] Release-specific testing
- [ ] CLI reproducible builds validated
- [ ] CLI released
- [ ] https://web.getmonero.org/downloads/ updated
- [ ] https://www.getmonero.org/downloads/ updated
- [ ] Update hashes.txt on website
- [ ] Update downloads.yml on website
- [ ] Update auto-update DNS records
- [ ] Update redirects on downloads box
- [ ] Update seed nodes
- [ ] GUI released
- [ ] https://web.getmonero.org/downloads/ updated
- [ ] https://www.getmonero.org/downloads/ updated
- [ ] Update hashes.txt on website
- [ ] Update hashes.txt.sig on website
- [ ] Update downloads.yml on website
Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 KiB

+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2019, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2019, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2019, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) 2014-2019, The Monero Project
# Copyright (c) 2014-2023, The Monero Project
#
# All rights reserved.
#
+5
View File
@@ -149,6 +149,11 @@ static el::Color colorFromLevel(el::Level level)
static void setConsoleColor(el::Color color, bool bright)
{
static const char *no_color_var = getenv("NO_COLOR");
static const bool no_color = no_color_var && *no_color_var; // apparently, NO_COLOR=0 means no color too (as per no-color.org)
if (no_color)
return;
#if ELPP_OS_WINDOWS
HANDLE h_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
switch (color)
+1
View File
@@ -86,6 +86,7 @@ monero_add_library(version SOURCES ${CMAKE_BINARY_DIR}/version.cpp DEPENDS genve
add_subdirectory(common)
add_subdirectory(crypto)
add_subdirectory(ringct)
add_subdirectory(oracle)
add_subdirectory(checkpoints)
add_subdirectory(cryptonote_basic)
add_subdirectory(cryptonote_core)
+128 -591
View File
@@ -1,4 +1,5 @@
// Copyright (c) 2014-2022, The Monero Project
// Portions Copyright (c) 2023, Salvium (author: SRCG)
//
// All rights reserved.
//
@@ -221,9 +222,9 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair
}
}
uint64_t tx_id = add_transaction_data(blk_hash, txp, tx_hash, tx_prunable_hash);
uint64_t tx_id = add_transaction_data(blk_hash, txp, tx_hash, tx_prunable_hash, miner_tx);
std::vector<uint64_t> amount_output_indices(tx.vout.size());
std::vector<std::pair<uint64_t, uint64_t>> amount_output_indices(tx.vout.size());
// iterate tx.vout using indices instead of C++11 foreach syntax because
// we need the index
@@ -231,21 +232,33 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const std::pair
{
// miner v2 txes have their coinbase output in one single out to save space,
// and we store them as rct outputs with an identity mask
uint64_t unlock_time = 0;
if (!cryptonote::get_output_unlock_time(tx.vout[i], unlock_time)) {
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)
{
cryptonote::tx_out vout = tx.vout[i];
rct::key commitment = rct::zeroCommit(vout.amount);
vout.amount = 0;
amount_output_indices[i] = add_output(tx_hash, vout, i, tx.unlock_time,
amount_output_indices[i] = add_output(tx_hash, vout, i, unlock_time,
&commitment);
}
else
{
amount_output_indices[i] = add_output(tx_hash, tx.vout[i], i, tx.unlock_time,
amount_output_indices[i] = add_output(tx_hash, tx.vout[i], i, unlock_time,
tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL);
}
}
add_tx_amount_output_indices(tx_id, amount_output_indices);
// Check to see if this is a YIELD TX
if (tx.type == cryptonote::transaction_type::STAKE) {
// We now need to insert a record into the "yield_tx_data" table to record the TX
}
}
uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
@@ -254,6 +267,8 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, const std::vector<std::pair<transaction, blobdata>>& txs
, const cryptonote::network_type& nettype
, cryptonote::yield_block_info& ybi
)
{
const block &blk = blck.first;
@@ -274,10 +289,49 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
time1 = epee::misc_utils::get_tick_count();
uint64_t num_rct_outs = 0;
oracle::asset_type_counts num_rct_outs_by_asset_type;
blobdata miner_bd = tx_to_blob(blk.miner_tx);
add_transaction(blk_hash, std::make_pair(blk.miner_tx, blobdata_ref(miner_bd)));
blobdata protocol_bd = tx_to_blob(blk.protocol_tx);
add_transaction(blk_hash, std::make_pair(blk.protocol_tx, blobdata_ref(protocol_bd)));
if (blk.miner_tx.version == 2)
{
num_rct_outs += blk.miner_tx.vout.size();
// count the current block's rct outs by asset type
for (auto& vout: blk.miner_tx.vout) {
std::string asset_type;
if (!get_output_asset_type(vout, asset_type))
throw std::runtime_error("Failed to get output asset type");
num_rct_outs_by_asset_type.add(asset_type, 1);
}
}
std::map<std::string, int64_t> slippage_counts;
uint64_t yield_total = 0;
if (blk.protocol_tx.version == 2)
{
num_rct_outs += blk.protocol_tx.vout.size();
// count the current block's rct outs by asset type
for (auto& vout: blk.protocol_tx.vout) {
// Get the output asset type
std::string asset_type;
if (!get_output_asset_type(vout, asset_type))
throw std::runtime_error("Failed to get output asset type");
// Update the RCT outs
num_rct_outs_by_asset_type.add(asset_type, 1);
// Update the amount tallies by DEDUCTING the minted amount
if (slippage_counts.count(asset_type) == 0)
slippage_counts[asset_type] = 0;
slippage_counts[asset_type] -= vout.amount;
}
}
int tx_i = 0;
crypto::hash tx_hash = crypto::null_hash;
for (const std::pair<transaction, blobdata>& tx : txs)
@@ -286,17 +340,77 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
add_transaction(blk_hash, tx, &tx_hash);
for (const auto &vout: tx.first.vout)
{
if (vout.amount == 0)
std::string asset_type;
if (!get_output_asset_type(vout, asset_type))
throw std::runtime_error("Failed to get output asset type");
if (vout.amount == 0) {
++num_rct_outs;
num_rct_outs_by_asset_type.add(asset_type, 1);
}
// Is this a CONVERT TX?
if (tx.first.type == cryptonote::transaction_type::CONVERT) {
// Update the amount tallies by ADDING the burnt amount
if (slippage_counts.count(asset_type) == 0)
slippage_counts[asset_type] = 0;
slippage_counts[asset_type] += tx.first.amount_burnt;
}
// Is this a YIELD TX?
if (tx.first.type == cryptonote::transaction_type::STAKE) {
yield_total += tx.first.amount_burnt;
}
}
++tx_i;
}
// SRCG: This is the code that calculates the total slippage for the block
// Now convert all of the residual balances into SAL
boost::multiprecision::int128_t slippage_total_128 = 0;
uint64_t slippage_total = 0;
if (blk.major_version >= HF_VERSION_ENABLE_CONVERT) {
for (const auto& tally: slippage_counts) {
boost::multiprecision::int128_t slippage_amount_128 = 0;
if (tally.first == "SAL") {
slippage_amount_128 = tally.second;
} else {
// Sanity check - do we have a price for both source asset type and SAL in the PR?
boost::multiprecision::int128_t sal_price = blk.pricing_record["SAL"];
boost::multiprecision::int128_t asset_price = blk.pricing_record[tally.first];
if (sal_price == 0) {
// No price available - bail out, because block is invalid
throw std::runtime_error("Asset type 'SAL' is not present in available pricing record");
}
if (asset_price == 0) {
// No price available - bail out, because block is invalid
throw std::runtime_error("Asset type '" + tally.first + "' is not present in available pricing record");
}
// Convert the VSD amount into SAL
boost::multiprecision::int128_t tally_128 = tally.second;
tally_128 *= asset_price;
tally_128 /= sal_price;
slippage_amount_128 = tally_128.convert_to<int64_t>();
}
slippage_total_128 += slippage_amount_128;
}
if (slippage_total_128 < 0)
throw std::runtime_error("Found a negative slippage total when summing the burnt/minted amounts");
slippage_total = slippage_total_128.convert_to<uint64_t>();
} else {
// Prior to activation of conversions, the staking reward is purely a percentage of the block reward
if (blk.miner_tx.amount_burnt == 0 and prev_height != 0)
throw std::runtime_error("Staking reward is zero, but block reward is present");
slippage_total = blk.miner_tx.amount_burnt;
}
TIME_MEASURE_FINISH(time1);
time_add_transaction += time1;
// call out to subclass implementation to add the block & metadata
time1 = epee::misc_utils::get_tick_count();
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, blk_hash);
add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, num_rct_outs, num_rct_outs_by_asset_type, blk_hash, slippage_total, yield_total, nettype, ybi);
TIME_MEASURE_FINISH(time1);
time_add_block1 += time1;
@@ -326,6 +440,7 @@ void BlockchainDB::pop_block(block& blk, std::vector<transaction>& txs)
txs.push_back(std::move(tx));
remove_transaction(h);
}
remove_transaction(get_transaction_hash(blk.protocol_tx));
remove_transaction(get_transaction_hash(blk.miner_tx));
}
@@ -346,8 +461,14 @@ void BlockchainDB::remove_transaction(const crypto::hash& tx_hash)
}
}
// Check for yield_tx entries
if (tx.type == cryptonote::transaction_type::STAKE) {
}
const bool miner_tx = tx.vin.size() == 1 && tx.vin[0].type() == typeid(txin_gen);
// need tx as tx.vout has the tx outputs, and the output amounts are needed
remove_transaction_data(tx_hash, tx);
remove_transaction_data(tx_hash, tx, miner_tx);
}
block BlockchainDB::get_block_from_height(const uint64_t& height) const
@@ -440,590 +561,6 @@ void BlockchainDB::show_stats()
);
}
void BlockchainDB::fixup()
{
if (is_read_only()) {
LOG_PRINT_L1("Database is opened read only - skipping fixup check");
return;
}
// There was a bug that would cause key images for transactions without
// any outputs to not be added to the spent key image set. There are two
// instances of such transactions, in blocks 202612 and 685498.
// The key images below are those from the inputs in those transactions.
// On testnet, there are no such transactions
// See commit 533acc30eda7792c802ea8b6417917fa99b8bc2b for the fix
static const char * const mainnet_genesis_hex = "418015bb9ae982a1975da7d79277c2705727a56894ba0fb246adaabb1f4632e3";
crypto::hash mainnet_genesis_hash;
epee::string_tools::hex_to_pod(mainnet_genesis_hex, mainnet_genesis_hash );
set_batch_transactions(true);
batch_start();
if (get_block_hash_from_height(0) == mainnet_genesis_hash)
{
// block 202612 (511 key images in 511 transactions)
static const char * const key_images_202612[] =
{
"51fc647fb27439fbb3672197d2068e4110391edf80d822f58607bd5757cba7f3",
"d8cf1c1bd41f13c4553186e130e6e2c1cd80135ddb418f350088926997a95ca9",
"95d2556c8acd1457dce7bfd9c83b1d82b821a55a9c9588b04b7b5cf562a65949",
"4b5d987fee1bb563a162d23e41741ad73560c003e26a09b6655f09496538daac",
"1d25ea86323d1578579d3894a54b99ea1c3e2dca547c6726c44aef67db958b02",
"92e46fb70be5d9df39ca83c4fc6ae26c594118314bb75502a9c9752a781d0b33",
"924d0cb9060d429be7e59d164a0f80a4dabc3607d44401b26fb93e7182ab435d",
"f63e4a23fec860fd4c3734623891330ac1ff5af251e83a0e6247287818b8a72f",
"5b14c5ef13738d015619b61dacefc2ade3660d25b35ef96330a8f4e2afc26526",
"d5016b012a2fb6ca23fd56ece544d847962264b4aee15efe1465805fd824a8fb",
"0a7f3da1d9dd341cd96829e484b07163099763ac7bd60603b7ee14f7dbcb278d",
"d716c03d7447d2b693f6f61b6ad36bd57344033fc1a11feaf60d569f40014530",
"23154a812e99ce226f6a87087e0812f419aed51289f1c0c359b0b61303b53a36",
"03940341e1a99d5b0c68eacfdf5a20df90d7d0a3d6089d39709cdd964490755c",
"ef09648814cfe071f5d8e9cfde57247ad09409265c4b6c84697bbb046809bd7e",
"8843ec52b0496ca4e895813cfe00bb18ea777d3618e9bd2e200287e888e2f5c7",
"8558bf39baf3df62b5d33cdf97163a365e6c44f4d6deef920730b4982b66449f",
"504d9380ce581de0af97d5800d5ca9e61d78df368907151ab1e567eb6445332a",
"673797763593c23b3ee07b43bd8760365e2c251a8a60a275528ff34a477110cc",
"25178c95e4d402c58d79c160d2c52dd3c45db2c78e6aaa8d24d35c64f19d4957",
"407c3a05dcc8bdcb0446b5d562cf05b4536fc7337344765215130d5f1e7ee906",
"4e7fa771a5455d8ee8295f01181a360cdc6467cc185c2834c7daf9fbf85b6f1d",
"6beb64cb024f9c5c988f942177fc9c1ec5ecfa85b7db0f13a17f9f98e8e46fe7",
"6406bfc4e486e64c889ea15577d66e5835c65c6a39ec081af8ac5acdc153b4b5",
"1b1da638709f9f85898af70ffaa5b88d5a4c9f2663ca92113c400ab25caf553c",
"da49407a9e1ed27abd28076a647177157c42517e2542e9b6a4921fdadf4e8742",
"3c3fdba2a792fddaeb033605163991a09933e8f05c6c934d718e50a613b64d69",
"82c60429171173739fa67c4807cab359620299e6ed2a9da80139b5b1e23c5456",
"0a19e5767e1381ac16f57cfa5aabd8463551d19f069f7f3465c11a8583253f3e",
"d0fae6ffdd4818399eae6224978f170f696150eaf699f2f218abc00c68530f96",
"0937889aeb3af5c64608d9a9f88229a068e53417448f00f9aa5e28c570cca8f8",
"d6072d269753020912524961ce8c6930cf35abe5c4b2bdc7fd678338d20a68fb",
"0e8bc9b06fcc842bdaa7df029bfd1f252d5defc014d58a006c10ab678ecf543f",
"9d42f90520f02c9258be53b123d69ddbce5f33f92a903d3fb4cf3358ff0e07b5",
"1cc05416b12cbe719617158773c3e6173435fc64e1ee44310dc696baecaeaa95",
"266b15222913c11ef6403ee15dc42c8c0e16bc5fa2f49110447802236e045797",
"791b123af3b71ac9497a010610f72207ff8ec642969b5cf0d2891b21e7eee562",
"946d4d7b084dc32495f22b35fc30394144c8e0ba04f3ad6e2c2bfb0173a2266d",
"2c015cb990c1583228d08b2d5de9227b950c3f57364fc1033bca5c0fbfd08c58",
"13fdc41862fd85507f579c69accb9cc6a40f5971bfa41e3caff598a3dcffd2fc",
"64b06d9874a83917c583c9439d1c736083377d67fda2961b623f7124663134c3",
"2fa49cd19e0aa02989991a4c3760f44be800fe8fb4d58b23aca382e10dc0d2d6",
"377628f265f799772e9fb6065be8b6eee200c329f729fe36c25ee179e4d20df9",
"ba94fa79134ce383b6a98b04dc6ad3d1b950e410d50a292bc770f9685e59fe91",
"875c924329f0733e31fe8d8aed70dc1906335b8a9984932b6368ea24edb39765",
"f31f4abb3f5ee42a5aae86d70b3bd9a9c1934933641893864dd333f89719d608",
"2bcd629e125514a780f568d3c2e8b12a2e7fbbee06e652bbeed3e7825508e31c",
"918b43581163ca1963de21bb9ac401756e75c3f00ac8dcfafc139f1ad5d7d998",
"5730dd57fa52749a0d6502b11c9d802ac495875542431310c674a65655b7c2a3",
"03f84b990683e569e2f6143bb963a2a8de411e7c4b7923117b94c7afcb4b43ea",
"b298c8510d35bd2be0ff0753ad7d98d480f4c6490bb67fb93cd4632ea726e8a7",
"0a771afbf9be104c01b89eaeb57073297d35ac8fbbcc0816820fdb9a29d26625",
"713d90d6ca1be1a4e05a5f8441dc528c699caa09eda49c09072f5f8291354c2e",
"988827f45c19330d9404309f63d536a447803cca7cb182ef005b074def09ab7d",
"9dcaa105b4def895f3faee704c250bdc924316f153cb972f3fb565beec0b7942",
"1c06c30afe65b59e9e22d6bb454e4209a03efe53cdbf27b3945d5d75b1b90427",
"49e08c13d1da209ec1aea7b7fbe0daa648e30febeb2aa5ffbaaabdd71a278ac2",
"e1c2e49ab7b829854c46a64772ded35459908e0f563edbcf5c612913b7767046",
"e08bb7d133490ca85a6325d46807170cd07618b6a5f6e1d069e44890cc366fab",
"5c73ca0691cde2f35b7933d6db33f0b642ec70d0bd3f2b0ebbd97754ca67e248",
"6404399151872a521dae767311712225dba65d810ba2feba209204221b5d772d",
"4a0c3aa6cef36f44edf08ad8fb1533d7e1186e317da8a3afb3d81af072043233",
"104b3e1af37cf10b663a7ec8452ea882082018c4d5be4cd49e7f532e2fea64e5",
"e723a46bf9684b4476c3005eb5c26511c58b7eb3c708ddf7470ee30a40834b32",
"18e6f0fa3aa779a73ceefabea27bff3202003fd2c558ec5f5d07920528947d57",
"c97e73eb593ff39e63307220796cc64974c0c8adac860a2559ab47c49bc0c860",
"13c363a962955b00db6d5a68b8307cd900ae9202d9b2deb357b8d433545244ac",
"76a488865151fab977d3639bac6cba4ba9b52aa17d28ac3580775ed0bff393e4",
"a14de587c9f4cd50bb470ecffd10026de97b9b5e327168a0a8906891d39d4319",
"b1d38ee1c4ca8ae2754a719706e6f71865e8c512310061b8d26438fedf78707e",
"772bb8a3f74be96fa84be5fa8f9a8ef355e2df54869c2e8ae6ad2bf54ed5057e",
"3083a7011da36be63e3f7cacd70ab52e364dd58783302f1cb07535a66b5735f5",
"2b1d892e3002aa3201deb4ffe28c0c43b75b8f30c96b5d43f6d5829049ecbd94",
"cb738aabe44c6fb17ade284bf27db0169e309bf8cf9c91c4e4e62856619a4c64",
"1707e04b792f4953f460f217b9bb94c84cef60736a749fb01277cfe0eaaa48c7",
"ab8b6bac9b8a4f00b78acb4bd50ed2758e0fa100964b6f298d2a943eb2af2b30",
"dd317193fef72490f3be01293b29e9c2f94eda10824a76ca74bf39dd7cb40ab2",
"4fb3d995b087af7517fcb79e71f43bac0c4fbda64d89417a40ca4a708f2e8bc1",
"549ba38c31bf926b2cb7e8f7f15d15df6388dce477a3aff0245caa44606849fc",
"7585c14ab9abbffb89d0fa9f00c78ecae9f7c9062e5d4f1fae8453b3951fc60b",
"953f855323f72461b7167e3df0f4fd746a06f5a7f98aa42acdce2eef822a0b2f",
"0931932d57dde94dcfb017179a5a0954b7d671422149738260a365ca44f50eb8",
"a3d179d16a4a275a3bb0f260cee9284db243abad637a9dbe92d02940f1c7ee8c",
"959843f1e76ff0785dafe312c2ea66380fdc32b9d6180920f05f874c74599a80",
"fbc36b3e1718fe6c338968b04caa01a7adb315d206abc63e56768d69e008a65d",
"f054de7eac5e2ea48072e7fb4db93594c5f5d2dfa0afe8266042b6adc80dfdca",
"39dfc68dc6ba8c457b2995562c867cef2f2cf994e8d6776a6b20869e25053f70",
"19ad7ca7629758c22ac83643605c8a32a6665bae8e35dbc9b4ad90343756ebb3",
"e89e80ea5c64cf7840f614f26e35a12c9c3091fa873e63b298835d9eda31a9ea",
"572c1b9a83c947f62331b83009cc2ec9e62eab7260b49929388e6500c45cd917",
"df0b21f679e6c0bf97f7b874e9f07c93c3467b092f3d9e1484e5646fda6eca5f",
"8f3b7c0f4b403af62fe83d3cfac3f1e2572af8afa4cea3f3e2e04291efe84cf6",
"aae8b8db243009d021d8c9897d52ee8125a17212f0a8b85f681ad8950ae45f0e",
"3d45a4957d27447dea83d9ae2ef392a3a86619bfcf8dda2db405a7b304997797",
"a5b0a619a8e3030b691bdba1ed951cd54e4bc2063602eae26d9791fb18e60301",
"14650df217dd64a2905cd058114e761502dff37d40e80789200bc53af29b265f",
"fd6a245ab5e4e6e18d7ba9b37478ce38248f0ab864e5511d2208ae3d25017e5f",
"fbe0be6dd42a11feb5db5ae56fcbbac41041ab04a35f1df075580e960c8eeab0",
"72f3f1213d9bec92ba9705b447d99cd0a6a446e37a3c1c50bb8ece1090bfe56e",
"20df836554e1534f62b2a6df9ce58e11c1b9b4746ce8ee3c462300a8c01f5e76",
"5c3d2a81b7331c86420ad32b6e9a212b73b1c3413724a0f91bf073eba18e2f1f",
"63264ddfb29cd36fc18f3ee6614c4101ba7229bc5ac375f912590d3f0df982f4",
"5ec4eb637761c1c9dbc6aa6649d4410508ef8d25d61ad6caa40c6ee3236d5515",
"270c70940536017915e1cdbc003de7279ec1c94cba1ef6130f4236f7e306e4f0",
"c1d1d57a7c03f6ddeeab5230a4910db8355e2143f473dea6e1d57c2f8d882b76",
"218c030a7fdc9917e9f87e2921e258d34d7740a68b5bee48a392b8a2acf1f347",
"ac47861c01c89ea64abee14cf6e1f317859ed56b69ae66377dc63e6575b7b1eb",
"23bf549c8a03f9870983c8098e974308ec362354b0dcf636c242a88f24fc2718",
"a3ce8b817e5212c851c6b95e693849a396c79b0d04b2a554de9b78933fbea2b7",
"7310120c1cc1961b0d3fce13743c8a7075ae426fe6cccaf83600f24cee106236",
"8fa0630f193777dcc4f5eccd1ad9ceacf80acdf65e52e4e01bf3a2b2fdd0dac6",
"4a5f5c87f67d573d0673f01abaebc26eaa62e6d04627588549cc9e6c142dc994",
"78971cccacc645116f9d380c167f955d54b386a22af112233f7de004fc0c8316",
"badc67216868e1de1bbe044bf0e6070e6ee0353d05c13fa0c43b1897db5219a2",
"c45b2a168bc51cbb615a79f97432cc4bb6b104da9cdc1fc640c930657452f71b",
"c17eda13541d14554c5db542155b08b6bf9cb403d425745b662ebc2b2b9b3a3b",
"313210cd9d2efc1603f07859bae7bd5fb5914f4a631b943f2f6ff5927a4e681a",
"6ee94ec8af4e6828f9b46c590ea55da640ef50e810a247d3e8cdf4b91c42d2c2",
"505b7a4d9f1ba6577aa2a941843f86c205b23b1ea21035925e587022e2f0aeed",
"98e6a7cd687e8192e300a8202999ec31ad57bc34f656f2ae90d148607ff6d29f",
"1be5db002c0a446cc2c1da363e5d08ae045cd8f5e76c8cccd65d5166393c0bdf",
"17c02ac6d390c5c735e1e873c40294220e89071fca08a5da396a131fa1ba8670",
"2540507c39ae6fdcd90de826077f0ca390da126166a25c15c048a60606a27367",
"5ab9328e525c7a017ef4f591d995ad4595d74cbf8ff4112af33b08c70661a304",
"9c105587a96c51d81422f64e46016564d22329760648c95dcac7218f3733f915",
"525afb1b94a75f1edc2b55c700071e14a2166acda003370047c30dba8ea80278",
"745d4a5d9f95ca4efa6261b6bcd4ecacd504b5b901a2ce1353c522a5c0c15dcc",
"5a5a568cd87ba34252ba254e6a320e1a7f52f13e7451bb887efb34ff881785f2",
"1ec50a80198cd830b51f4f7a0222015a268d9b40f04e7f838c7b8dc7abf63b01",
"68836b662d79349cb42f5cef54e6a066157d398cc87d3b13f29fc04e5cf364a5",
"658db317f355a9cbd86f673775cac0c308fe14967428fd283a36e300a6a53b2f",
"677d79a8c467dd9db38f0ef45c2787dd368f701a6b47bf7a5f06112c38da643e",
"2baa455d4066f5d628f9ecd315cb57deca71069db5d0d112ae0aa18a84b6f0d7",
"5e7b0889f351560081360ac2b1429b48b2f7d886227f144e3b198e2f1fa56ed9",
"c3d317fbf26e15add8b4f8f93df9de9b22297b8e4945ebab9ee249d4f72f4e45",
"3c0b705a5c1e31abc7e46d8ff3c148a033f6875454cfb67f8d2a2b9a57a5ba7e",
"a0ab74663561af2adc2d38be3569fbe7aa2454346416ac96e5eb26b1e01b1e2f",
"53526cffdb74327670566c1dacacffb7d30a43a7f1862ff8bab87737bfa5edb6",
"24c5d36ab98d88f87b2c71afb4ea8562e05c7aa0b50f3bc0f9ed50a4cd52989b",
"c3ce4de5f94dff65d11e33a865855a4404259cf45263914c884f79db4f35169d",
"f1009b6dcf30030cff872d636fb96ed233eb6ecb8ffed003c7da64e4f5a02f4c",
"e3729f58614d3b42450d1599d863983ab7e3e5c29fb57aad7958c8923a2627c4",
"31cf4792f7b5ce01b217ec80184edd2a7c49c0b21701f5494ee2c9bac67c28ca",
"b42a5c9c92a656c5bb2b759ce160fdfd245243aeb1786338faea63b62e9a60ce",
"a1efc8d5d0855933d5ac8fe5960c7acacb92fcb09bfbc929e5002f168251e648",
"c4322c7f3682ec94b0dcb42f13b498c36cf575d505aacc8ec8bf67a6a2abf4c9",
"684ee5aa3c98357aeaddcc30c6620939b52aeef729e24b4a46ccafc44f24d831",
"36180f2ae11d105e0efbfbddb94e6b45b08609a383e4e1a8fa3b06d7a8051de9",
"96c2d183eacc87581a0b17b8d07878bc10d436728510715109a7565d9972f8b5",
"3068c9d04d561c7e29e3f621280b61a61885de0e9ec35a66a3116ca7a9e09627",
"2eb94b9673ad6f8f88288fddfceae4baaeccb37bed88a35611d826ba06a5363b",
"fc8cd5fae8b81121001f7767dcd5f185c0fdcc88cce1fbb184ddbcfad697ba54",
"51521da1ecedea6d588d774eb155d936b32a14913c2f11d989bcc5116e65bf41",
"3d23542e597a83dd6307700d79058b920f281c65f832333734d8a0adec510495",
"11d2e01913ff0d4bd21970d709d88e63289492c0bbad7bff99c0d36858a841ca",
"de674f1eee3068d2bc8c2f2897d8556e5deb872869652f7d3a4e5dbc6f1063c8",
"e722d7f728526110c0921791b417afde4af1e87ae48ccc01911786197843104b",
"aaba3a4e2a7d20ab76edfbcccefc27acfd509db3638582c28230e73ffd71d340",
"1385a7209dafb9622dd4274179832e40c7fae19445383c34ef79adb0e4de0c98",
"108408531fca288d74de4a2c596eab8569e355d9ab2f8380f4d24073a6b3fa95",
"294476a86fcd39351ae452cdb8af9584067ec4501ec6182d0062bb154559fed3",
"e64b175e0284c5cb69c8db46344ed43b5ced8abfe3cbf0c197103cfd116944cd",
"cdd73a0f1fa7c14ed2177ae2163035333718847e49dd5cca6775bd20fc7553ad",
"d423d2a374bc66a4587a5e3affa327ca75b8116051320759a3b88a868a7b80d4",
"f13ad1e5b1315557d5497b58516eb3b0759d909725ddd0eb8a0dee439c6c0a48",
"3a600b547a6061186a54e491344fd50cc7d4f0566a386a40aba6545254773728",
"37a6f3f221fe17cc04a65aa544d5135e8297ecaf0853ba784dffacb74feb481b",
"0ca42d67d0f84b28861d63e919e6ce5ad527447fdc53a03d8497a0241bee9376",
"c7dbda42459e6fadb92c416eaef3e04674fc57915a93f3be4e656634c9654075",
"0e34d728ae4fe347a5afecdf886fbd4d48a65c5d0dfab807da6ae95b6b2d7a3a",
"f1bc69257ed510db5b2ed370010b037f452a29c49e36337264b3011ce2516216",
"33f98f6b8a8e202463955998fba3b790199daa893e5471554826cfd9daa5c02f",
"f8a0a37a2c9ebd7022d7cded1ee0318fd363020070b4cdaea800e44dcc1300d2",
"6862714daedb908a4d86a3a3f1e65ec2c29ae61501b4ddcaf184243dd095d71b",
"555cd19a6d21941c1174129b8bbcc70edcf0d6874262ce9e1e542351990d523d",
"2cd6b44326828f23a2aa33699754bfa072c4883f39d53616f6a6b74149b664b6",
"127f45d2eacb565c21c1030fe8054fd0a3a75705bc368924712aa145d414fa47",
"19225e2dae6e1166f21cdab1290194470ded09df9b66f3faad3c1cc9ebcf340f",
"b7b3f53f0539b2b4837b8bb9dae0ccbd200c8d36126d9f50199d68a4293a46d3",
"6b6323be01f27d6d759d9670825e8ebb9c4cd8016351702328df91cef36cfec8",
"020c31cfdfc5b22b10235745b89b311d271cf82f2ba16d03fdf7a8bc8538694b",
"62573218530182b79e40d0113b7d281dace6da33bfcd0f9318558de5e5c76f08",
"37d928416b15982f5bb8be40c5b62fae0b664e412c25891f8860c4242927e610",
"b07ad11134a5c0542d2b418ef3863e8ea8477de68d9310681818ddd40825fdb0",
"4af77cb76bab845b56470c95ce7b8cd84ce49a095984c1f3eed67b0ee344316e",
"e3fdd4668d8726ba6adc401ac662c0cf6b5c1872082c488ed7da966d425fb1c0",
"3dec71c81c7e78e879abc8da8b30e2446edbe98eeb8df9dafe9201ebb4c6a834",
"7105467d9c5e855f1362fbddf820ed5e757997862efc9000317d3830a2f60ef3",
"2821df94b021d3e77e8d9c0f3972340210f5ea2c0935cbf125cfc578d4d6722f",
"114e5807accc337a22598bded30ebf3e0cfd75877e239f10cb043f829c315ab5",
"d658a1c0354628cd7312593ab25d5b9083de8f0def6e8425f188101d256cd136",
"4818d3be9b2a38fcc8c85d6c46f69b502943f79cf2462dfb0b6499e761bcc836",
"92b8c943cb017b5f2d39264640c069f1ecced1d3ce9b3fd755d6df2fddb99458",
"6edbd0fdf064fcbccd4a9e7a8ea520b87cb7faf867f7fe8a5f53625beb575119",
"bf3b49c477dafb06af65bf09851c0fbef9dbc3152a7268d31b55a8e7a9a95860",
"0e234dbadfda1393be2f068182615dbb83736f84f87710b5c7965bdce9f4a26a",
"df5ceae34429e47b92bbd5505ba27666552e0eb619997f359c55699c3252b1ff",
"08c1c7d940d699a91a83249bd578772e8958ffe23179e6150f07b96f1b47ce1e",
"6f919a429270da0022d70062537bdc1b21c43a8abc552d8e366647e5b719d310",
"63c66e5fd5d27f6fda87912ce46fa91a5e5b3634ed147fa2986330fc2696d3fa",
"bde070b75296bca3aa494e7f549cd2bd1ff003776712bc98a3164b139b2054ab",
"66694196dac5b60cf5e0ae05db8f3894fe04d65910686806551f471a0a0472e9",
"0d2e97524b7ce4cf30b54e61b2689df036d099c53d42e2977b1671834bac39e7",
"e081af76e923455f408127862be5c9baf7de6b19b952aa2a1da997d4dfe594c0",
"121bf6ae1596983b703d62fecf60ea7dd3c3909acf1e0911652e7dadb420ed12",
"a25e7b17464df71cd84ad08b17c5268520923bc33fe78c21b756f17353ea39a0",
"e985f078fb44dbfdf3f4f34388f0f233a4e413e02297ee9a7dcc3fcceacd44f9",
"b9184cf45e6e6b112cd863b1719de1bcab2137eb957e8028edca3a204a9ebb96",
"157d177d5e4bcce0040eb4bddb681eacf9e2942e1c542a57ce851b4742a9cc4f",
"0823e06635c9a1a69fd8833d1e48df98d711c1c47c06f27bb384932db1bbe9ee",
"8beeec1fd1bcdecba235b449cc49abca69b6486ed1c0861a2bfb6a43c970b86f",
"349f61a1cfc9112e537522858a0edae732a2f8434cf4780d3d2ec1e96f581cca",
"587cdf72b5914d364f7e214a70481cf1131ee4a09e6b43e52428d2e56b000c13",
"a6aa0c179316534c7b9ffb5f42a2af98d1d3a166bfb413199579f259c7b5e6df",
"f9f3bb1ba8da5899b79186008ecfbd416b49f3b86d94045b91e34a40e41d5cff",
"0cdda65a60b7b4d94e794c9397e01f69fb29309ce4fac83e7392dbba6bc497f9",
"8fa5fce5ad09d43af7218ea5724cff2c4849a59ff73caf3bbca466e3c8538ba8",
"8874ef46008753fcc0b77eb7a4a8560e35966bf5a12bcad4203ad2b4c1f8bfbe",
"a8ee9a3aa2d0c08a951439ffb0e6d10315fc4776997b275de1ec19663e88c2c2",
"9c184cbbff464ab4d5f6bfa78c39bf0880fb93b1574139306a97acb940d415c9",
"5493a38c255c91ca49b958ed417f6c57e5bc444779d8f536f290596a31bc63d3",
"3e1e82b96cc599d9fc55ae74330692ccbfb538a4cc923975fd8876efe4b81552",
"16aaaf820c24c2726e349b0e49bbab72ca6eef7b3a2835de88d0cececa4da684",
"7fa52ba349f7203c3dbc2249f9881101a3318d21869dd59f17abf953d234db65",
"713d8018bb9ba3ab55c3a110120b9d7593514111075ef05f0fdb233ff2ceddc8",
"56063afb495759a0942f1c33f28a4fb8320c6d376cb3c9513249453e45f24a04",
"f9a6bacd9e055749b45174ecf3c3db18b78f3474761948a68adf601f54e59660",
"7ddd7c6d41572f93fe07c0300c34e455b6d1f4372204933bf45035241c8b060c",
"f81021b893a36b201de71330a2ea050b59dbf7560c62fa9cbea9261ab47a0ba2",
"a01fbe4114c18fd534ae1621404d25c08e3b6775a2631ff40279bafd8c9304f4",
"350fad8ebc938c6eb508a1483f385f577794a002bc1229db70a1b0131d174b9d",
"570cb8bce87f532c5051d8c4c864012408e672a7d492669e660251fb1e066bec",
"8cb6efbb129c84eba26d894c4293b476a6e9a1fe969c6ad18b554d2a57885f36",
"f384a98467bf7f084ca31bea121a4ec76e530f523d3225c21ed25a18544a9916",
"da127ab58ce557c2c95c20d6a291c2e5d880fff09dc28927b7bdfec97b995d72",
"a4d95b4f74366ec920d0a0c5d81265688cc18733ffc444cac9b01ae2431568aa",
"5ae2a71470570733422468bb733d53c85b1c8a6e7e6df5c05941556bcf342d1a",
"65a2d161ff0e095d3afe37584dbbe649f1e9cd440755b5a3c5b2a252d5c0b8bc",
"25ef70a8e41bb422ed7996a41160294e33238d6af17a532232f0a50b123431a2",
"f1f0f76ee901664a65b97104296babb9c7422370e99bb677ae07c2ee420e7f40",
"c3c66dda180b0330e75c8139b9f315a8c6b937f55d87d7be42e172bbac60d71e",
"5881786695a9e58e19d79f790c7d9243a847c0269c5770bdd01f5149c2a62a88",
"f2f816d3c8ebc7df06ab68d39223181aacc7be04364d1d4e69a56c33949bb983",
"80a1c3b6b2778d4846ad9fe0bb2dd5afd99aa897f8231bfaac45fde43d602d9f",
"72ad67cb043aa5df0c3dcc2464953a66893259d81c9cc7778c12bca3447fbd58",
"ad72420a7963b8d4536d8eba00b4b989992247cd8c01660e242a8e71edaf0e19",
"999d603d1cf6068e3bb6abe1bca976fa0ab84c4660b29ea8973de8b5cf5fd283",
"e137a5910f02a764c3a3d8f1579ac0c7e3cc34e58933216868efe010332c1e6e",
"10e0fa2362f59317626ae989bd1f962c583339d8d74d76c3e585243d152b91e8",
"1951c652704962f5c6e33a4d4aadfee5d53ce2253644d1ed542da3e278524a07",
"c938bccb7ba6c0217d8ba35ed91502aee051c8ae5bff05e88aab3b322aec936f",
"4d6386c689785edd5beb55911a3a9fc8914838c8192184199589beef8b6ddf9f",
"26f6f45a6468bc4b1f085fd28d63c264ee17564f9e247fc03ee179a0b579dcda",
"235b7bb82b72c61acd5979ca5f2ca740aee805a780ba22e11aae5cd34f6ec760",
"c027ffb585a1e4844b4907490b621b08c7e40a5e6f93e97bd4bb1b615bba9908",
"aa77fc8053d139b998577319de29457b78b1cc8b35a5f3526c0621eaa42ce6e8",
"afd0af9a11c5ae2a7c4a4571ce39ad57d8df70ef146ed83ad8eaff97b2387fb8",
"a1f8fee9f1da9a2b306489d00edf754187b55e97f4fe6f249432fe6c7f44d6be",
"4f12e8a123465a862060efb656299e6bef732e5954b02194308817b243e84d32",
"6a1ca62f7d6952ad2eba1c64035260319baf03deabf856ca860744fc886b3d3a",
"c72dd1fe890d6e4c1f7325a4f224e85aef6cdca8bf9441d228efaf126e02ba63",
"2f6ddcea18d891ef4252e657989de68adcc43c2175d49c0c059c5e49b9dd5aed",
"24efac0f240ed183c30398ee40307623f52113598f66c5864c90fc62643a2aec",
"6ba3ebc935e7cf7fbb446e7f5c12b19c4455e6894412b0eedee4fc945e429e9a",
"3519d6e5bc9649f97d07a07ef5471a553ffce35c7619f4f63e91a2ba38cbb729",
"65e073df352fa9917e5c2475167e6c523b68c1406e1b6e81109e2d4cc87c740d",
"d73bf816c3648a7d53d34be938c454e515efb0c974d5a225f33635540b2db90d",
"bce167790fc86a273db011757d09e2d1148521ce242c2ded58f26cc49993aacb",
"2d4286ed4039916f29602e86f47ea4c5b05998c0198509ca7799fcadfb337e8d",
"9837c495b1af4f76b09177514a0f3e1dceb509c52b91712f3c7d29dc1b91d09b",
"5c848b8291f39759903ce77f151acf40f3ab5afa2d4a45af62b320371c29a697",
"b92df5016ee947ce6a21365d3361977f7f2f6c14025a983c44e13d3e8cc72152",
"71d2f57222a39b1a7ed2df5e6fb23a964439b5a8e7d49b49d87e5cd5354baa75",
"88b44d0198fb15b0c20a97f87e021c744606bfd35eae2874f35c447aa4ac3cd4",
"29bb4c2557714119cd684da2867e689e37e3ca9c912db83ab84746816f6092ab",
"b1836d98a288752675b133b9018fa1edf174f311921d01926c1e1a5900c21029",
"a00645e090c7d96f3155ffbcfc41e526a763b0f53a98151ac4a7d4a5b14066b6",
"78aab09919d17773b0d62799b37bd2e2970f72f5d1eb6472489c367b6135374f",
"eb6123aeb28608f1c97b2bf62ef69f977cd0658a0ab491deebb1e972caa938c5",
"8dd7ef1650b1b30cdf7814ae4d61a237eb0acc3ec3ce0f72b1c25780329c2d7d",
"b1998419be3172858b990eea84fe10bb24b76c219cde277cb4305955fc7e0b65",
"1b10560016c4bc506eef9056dedc2943a17179081e6eaf85b48d37dc20eac3cc",
"1fb1d9d4d408a6734234910f554d272739a0d6fa401918d79b57be62c3f23ba2",
"dec878f54ce36788289b61d32de0d9539032aba22cd15522752f729659c7cc5c",
"fdbfd0773f5a66637b093dabf812197940d1134619a7e60a931b19915b7dab0a",
"21bd2c9aae052a1c187947d2964f2be4afa7b30248409c41a75522e88a4e7977",
"59326adab03416ec1d36699c18e5e4fa13ca1f2212d48c23bfdecb0be7263616",
"bcf263d39457c0aef8ef42fd98f8131198ec4fb203155dd5bcd759e499a9ca5c",
"f1ad083bcd8c7630eef93336d8a971ae8ae37166a6a00ac39684420c5f9afef8",
"d82ee2ac41b36e3c1787a01835bf054070486dc20f6565efedbbc37cd3bf5fa5",
"eba91a0dcbd3986299b0a3e66c116f77bd3421829291fd769522f01da26f107b",
"11016558b7e8c6386c6a3e862691dcba47e33e257f0e7df38901ea7c0eba894c",
"04f02795e34a0030e5186c8e700da8a46b1aa6bc0abed6b35c9c1cd6a73776b9",
"2628dc8ad7fb731d59456b2755a99c6701467125fa69816c21bfccabc31edf6b",
"9b7ca249ee5b45cd264492f30df09f708a7d9caed7beb9a5c6292f22e4c31f85",
"5c42e7caedf382092faaf392174792b3cf5f2fe29cb586387ee55611af0617c9",
"373f2fd5940a01feb79659c8b9099477f6d3e7b570ebb749c2ac336ea4be583d",
"fea22887147adc3a659a14902080b03e86b4b8b16985fdf0bbacaed00d812422",
"6a3e51a1443cff62af9fa12fafc8ea78ae74dac7792c9ae0f436f570ab33eb71",
"796be21e213d6d0cd6fbe2de1555fb73d1cf9edc041a9f1ff1ad583c4ca92460",
"03fcbcb31d3fd17f0eedb45ac5a51678c7c8b2b8498225d05f74e2892f017f72",
"d28da07c6c22daf9ae987b3033c33d3140e5a56fa1ffd7dc5c7853d55a45bcc7",
"fbb0ce02f50018741a12fc08eea80a18067d7bb0fcd96153d40bb8c808473aae",
"2bf7c05a0209b4ea31314f04bd754cd01c58102d7cde8c496c655b6494924354",
"1968a9e6e14ae86a1e02e6078fc4631851fce5dbac6aa34f860defd1ccfd0ded",
"d886181329c9e06462a1407f547d77b38ff2c868b86d8976aa478e1cbb3d66d4",
"0d465e02ff2f8eb0b5fb2fa9a38579c5d66337d4a16b58f8ed28d2d89fc02392",
"3196419015289807880ef24b6781734822d654dc260c0560d00bac65eacd5219",
"fa08390ddc333a2a12248d5ec3e51fff9b782227069fe5a0afbd8eba967ae8d1",
"49ae36a791cb84516688d59a1ed3e5112851d65f265078aa2d433b45fa984c8a",
"35daa428e12c59da6730760979aca3444d8b31149c6febd99fbfefa4b2372082",
"5ef1d697beba612ff31d1dc139817c313a4e2ad3977775943b635c141ef0f2a1",
"674256037ec00edb66b9355fb1d33a30a47a5d1f4bce2dd5475d89f1ea6502db",
"7b6f017bc550933af91eec32a79464f540c5e0c208703e175843ee4e9ffc0a50",
"bf0eb91da1d18dbb18fd9ff36c837387887ba142961176a44889718b2becb9dc",
"3e5ac43a05164b074a2ff6353e9882917c5a3dbe168c2695de895f7decf1a56c",
"35e8f004965347c2b18a000a83dd3a8084b8a4bf00522061ed1179aa1107c413",
"fccb0fff3a24e555ec96f702ec11d420338910d148fc7b039d67568ad3a0e032",
"5cab231048032dbf921b4fafa1951dd2da93bc3740667f31d5a1d5665b141261",
"ffedb24be73441fbcd069f7785ebb865870e0f3ed228190732e4ffd5962bb82d",
"a4fcfec18adf92f4ed822f64d2da9f5ae630885a1bfa626530f641db99aa7a30",
"f98bcee41b0e3deafa1efaa1863750dbfd9bd7430b82529b670867d852230b5d",
"8ab8d5fca047a52364a737c1af57bf656c9ad5049f08ef4c5aa252e61aa72123",
"91318b39ad94c1d58143586b6d90dd6092a9d7487e321f4976967b6ac445ff43",
"fabfbd4569ab018e12d5ffa9b1a40ca8eb2ca60a685817351d90eaa770d5eccb",
"bbc5ef34428d980e2401942ceecfe07cdf21bfb1acae0596ea1d43fccf504f69",
"26943e4201ea407a5667103fe07ca6e08ef76940f274349b0e2e776bcfb0acb6",
"e3b305ffe33e72841f8e2a8688cc5cc27d42aee7624b33b7b6399b42db392437",
"17c5a763dd57e6bcc7c4cf2db0eb5cf3e97116b67fe0dd519c97e4a4d55d5a62",
"bbd260216879ce86af8318ffcf73c9e063ca76dd8bc35d3b6be45b2b4184888b",
"41285591d0595bc42ab663051b410d51af39fe1720592e27acb1a8af72360a76",
"f29acd6068ce494d0c0fe294cad91bb8968e3fff3f595a113227ab545c3ca3e6",
"ec9013c6394528e7dd788ce7cc085ca79fcdfbb37565999d5b4b5a4e39452ecc",
"27829bd7f1a8fcddcad0cc34a3b3fc67d62a2f3e09f8e75d35035c2281e83afd",
"666bea9db4e15087204d076294d221d4cf5864f5d94de38f29132b1934a17ace",
"a3a30924cad3dbda3446e5a6324e0a1390c70f795d5ecfe17ee5c70b14f7d87d",
"19567fe5fdb10711d60aa4d9843e1c49c2a6d2fd1b5cf662e2105606bb7815d3",
"b139f1c3a2f15596b9320334e37e4184d5d584c4a81e72d821a7edcad3aa62d5",
"08f1531e0e3e8f8bae313b2c60a72d5601bf8b60d7a4d2f60e8481650340d250",
"c5895669e1ff182bf1dd6c00dc955265e08ded0952b8ca62a1c63ba11c99f4ca",
"84d1c28153f66c1a4eb5fa0df695e936d83294df31a08d8d8e2d4798d19d8ce0",
"b8699f6af853fdbe897848feb46a05d733363f304eac4c8c1932e6ea4bc062cb",
"10eb3f6c1d0661468d9ed83593e5e9c0b43c6feec6a5405a498194905ea6ed48",
"509e215a600d9cadcbf5d62632ba321d7314764218db00ce8c907e425fccc445",
"e62119b7be84c8eaad41ba7f4a35da403f4ed96b967a3134e89ee8b78f8792c2",
"f790754a95d59ea5ffe6b9b5cc386c600a9e19e8bec997c192764365f1d05376",
"990121b5aa4d6badfb7154db4cdbb4512124bc2f442bebac71ea90b5cc86f203",
"b6983dedaa891eb14c964d84461e5cd37ed27b61771c64978ba83e3ecea194fa",
"00fba1ceaa6aa1e378cd5b22a771d6070250ac37f4e17d7bf1a70b3139e9a860",
"429854e7738abf2ecf46909454039e2fc5a080eb9a3c0c5ea13b07426dac3ad9",
"ceb3e017944b0dd787be219d8629930b3f2e20e22b12dc88fd838488ebb896f3",
"eb9e5d14424c63e675fe771b73ca865f7d38cf334d65e2426e12a0b88c1a2236",
"556ee713449e6e59ac4b8b2e8310180c8f6280484e9db23456526cceb9216168",
"bc89c3aa889e0144ac526a1f861227430dde7e439cc6a7e9b25c9a049c3ca7b3",
"56d070c62ea99be66fff741a8e45fafda5f9ff783e84d5395b251f356ce4e16f",
"ace15859c399e5ecd13b1420d3c3703c6a88dfb4a084f7225e7ba40a4b444fc8",
"f03f1261ab6eb879fe9c5b0028cd400b3ffdfac4344e4c75f6cde3c05ded1f26",
"955b2fda8d0068226f89270028b316b5adac871f1c1c85435479aba14a381b0f",
"422509a98d7461a6b8ec87cbb173b2486577b59ea9b269e01c20567b38b3b3b2",
"007d4de62ad89a4f5985f0cd9b76a7293acf383b4e9e734e813b9df1d57f986f",
"13a04e32948225b7e22aa0137341ebbb811e0743032fac16be9d691a652db2eb",
"8244b11d880a52f9f9e1830a822e6eeeaf0b12fc759f8261bc2f490cb0794f3b",
"27d3415f8f8fd3048a1ee0d9487256dd1b0f9e31be663778efa5b3add63868ec",
"0053f888db916a8905320e253fe2f0666355e6fb6de36f897231920a3edfe39f",
"0bc5c0a2ea47fa3bb8be107e3b9d6b7226b1c8bd16ca1bab8f51b8e1de08aa8b",
"4ca13aaa161c79025b5cd6c9a8ac33554f5ceb479fe293d9a342c865cd9c9948",
"333afbe82e2a3df38bd1ef998f39c5feef2554697aa21b5410c0e95ef9156249",
"587c4fcabd18ff890064171fce3d5be0c4aa1bba46893fb6a827a85ab54d20f3",
"964328e4d51d67c4e2f1fd102a66b861d98199f81d18d660b1b4b52504cd772a",
"196aad5594651efd679d30b9feb0f0d172cf977b4f89aa670ec741a8bf21e669",
"9137bfd66bbf47bfa0bfcbb9f6e71b6eb3fd9776530e9fd30d3dab19e182f35d",
"8217392c4ed2313188f295d94148a027a7f43824a5f5fba33a0b8c1045d509b4",
"be9e12761519a4836e73015544163254877e1c4912fcea67a10e7026421dde75",
"7b5220421a520b876cc6cdba0d3895104d7fac914dca5b93f9fe8b226566b71e",
"5c83fccfeb4bf0eb8a94d43ebc84a81639a32f26c7ef77d0a2b626b7de7befdb",
"132fd6c92cf176f975efdb5ded53470b462a48a2815c6f54a93ce4f935784cc7",
"46a3dba364022d11aa616a2bc20e3be5c4390f38b9446edfa464d90d9af5d48f",
"34b3f3fd8a83905a37762060f51d0b116377b4820b031b8e668e16f46c5b0285",
"f0e397e033dabec859a4b9a9043c5f1fb0dba504764d6bcf2fe9bf2ffd318474",
"85ecf59c7dd3b24ad17f591bc4737f32f1384c370a7a6f2add06a811dc824b6c",
"4d03cdb1e6ad8e066a83654626d8c221433e8d4fd901c671300af37e000177f2",
"61cb9c651893e6401b25f2bdf79c9f3ddc9ffe69cf6c791c420462bd73e347e1",
"85f2686a42158cd5ad327781ecccd1bdcd346941dd4b4edc45f717de6a011800",
"92de2ab82cac528e6d4ccd61e5b7c79591dcad9909c8ad3c8276ece6d48c0f08",
"23a878a06bb94bff33083349149f3c860f2b00bc3fb28f04cbaf717c08af19a3",
"1b1cce18ff0323566b192885d7ced30f9a9531a2580240f2c593a7d5b8580974",
"08fcdec7ea1376d84f3b13a47a4b73c7781c9c7890bb28f712b58af4fd3f24fe",
"03cc08fc4ece807c6495272c412be23b045622cc6b786ed8d5c94156ae678a0e",
"c4d8a61dc3f5dcf4b83f27a90cbc37e816cf4754e12309626ec5679c99087c46",
"b29d00681e29001cdd63c4bc50e5e25715faef692aeebb678c8050e1c095e888",
"ac154617e93f2bb1afa232675f2135437a9cc9700c14c51c40084946596ba11a",
"ce9549de8e68ae89f424dd9e1cde8a4eea2069da667cfcfbe837691d37366668",
"426c45a98e2af35cc9708149f6c086ff5a3972e77d62c627d5e20de5d731cad8",
"7e21bfe240a3d9b77a129c734a1d428dbc890379fbaf862853f48b2f7470b2b0",
"fa090a71f77223a7210de6db18d9aa809e89fb15253aea28131df6c5a7639140",
"7094ad044c5ab025e088b43aa0b947601fabe58ed700a412fd96e4b917ced0c8",
"936d5cdc4f081b6fe36c356af4378d472cd7990303f2ea44da645afd7d5d7f9c",
"05342037d3b69349dce7b95529d4b2a63ceb9d9393217a68f7cc8c958a96c3ea",
"ff9e1c414ef27b1178b1de296526f50520b7ddb06286bf9c47792bfb449e40b6",
"2f2b7bedb34d2854b17ccb702cddd8bc0157e39721d58be0b2ad54ee291fc9f1",
"0d8db1f34140bbf7eb809137018a74af08cb3345b8a3e368cdda8521dab45791",
"b109e4bfabcfe4a1c38be1156d9ca851c75e6aa2e57c0869e40cd9056f571e07",
"5cb363547ca077c806fc69bc8c2006831ab89e72fd778ac1a48fa810934e350e",
"85ee928bb110fd64eae54a91fc8548883e7fc4c60a3c61b505c31cea2d295c86",
"1ec3df7d10ee6fd5f0532ad4fe771e6befc28b0bed0250bf523695d6d49a8246",
"de9db2fc07c866bd7b885fb41522b63d550d0ce2e8ac5e14464a41733c2319e6",
"9a27136422a8f56768db29ba172a7ba26c3c7aa910324e78e5ab3a3268ac3674",
"60213c315119bf9005cb533d1a5b403b4a13c59982fe7773d30fdd8f519f4205",
"40eb61ef1812eb8a4d389599bf449fc86653b2c4986061b952f46fc049de53f4",
"658ef0d8140162b5f04591be13b47456245f531208bbca3260b857ca09b803c5",
"02270fa66255048d724894e2206b4e773cc6a7b6d17ca090cdc25f317d5f53b9",
"2ec6a0147f419161f7198d05be5f93152d9ccc10672db0ea47ff1687c0f0dd15",
"4be1d8ceb96eb80ef7ce30079ded31163272aeccff5c18fe3aaa32ea2f5bed9d",
"04ecaf48f44de87243b17b4c71ebff00020738639336010fa57435a54b623798",
"e313a9feb7cfd1d56ec87b1f1062ff9a80da498f7b761af4bef0cecd1b4c385b",
"ede3748f971f22341f7f5844dc60fc03cdb30c7cc720ebe13ae588c17a78aa94",
"d90c0faa70e39b7c0a8c55457ed6e6478a4e4bf3707b08104326a1ee8377c3ab",
"c79ffd0bbc8d004cc542e212990df6498abddd3deb50fd00ed00a2ff690974d6",
"35c37d88cf73a89c4124b0ee537347c37fdb47156c8b0ecc509efc58236ed3f0",
"a99182f343ccf05e557ffa6df71f03688b2afcf314c59daa774fe78db6f47add",
"01115397a78af8a4ae2727ca7a01843235b626bd3db80888d3dfd0020d4135e2",
"4a55aced578470d2f7280096d7fe8095f294095fba4778d1977d6db9270472f0",
"4624adf8a5633f65b213b8ca46b55cb0ee36c41495f39b1ae70cbd545779b1a0",
"d72bcd5b57a9c47e7bd5e9a1103657d10beb7b6c6d41f2b2985bc3bd3cc74860",
"48baadb9a46293c92f29e7617846171356a42c3b5d18d49a05a7e173993785f7",
"3da927737af8cb0e1c77097e35c54158d18aabfb3051c45bcc7ddfe00b157b1f",
"b4a24bfdb2cb802c8d48a3a18fbfe18622a767fe7eddfca57d4555550ccd1643",
"c58f82ac7c49dcba1721a88358f07636c9df60d3fd383e5789b808dc57a1dc9d",
"5e1f756eff5155df073d30f4452bdafc4adaf4f35960771bf2c1e30137fd7a79",
"be4a332f289338d67bd4834eae3128c488a61d255e972da484b6252b67a46b89",
"d496e4a36238d03a83d8b45cf33d9388aa7568a279b034d1cdd87b457356cc5b",
"a1c5212730ccda34de393210e276bbd44720dda777bcfd602315a3eee582f7dc",
"08914ec63f6ef7fe1d678937dc0f6178883440b26b4aca29fce79068947e8397",
"49e2cd2bd9b974074d9814f93eed371620bd4ea5fbf97a625065704e8fb382d7",
"047c194111818b48ce93a4b006e4a09b9a2650757a87357111796e11e847bf23",
"5955b0baa8265341f35a6f24fdc79066ba3ca9c5354c69b6b37a9ef3a26be556",
"d7c962f3ea1938c5267cca4072548acf3afcce4d438ed62027caa211a5f98e8b",
"c8cfba67cb4ce7e291b35154a50476d9a5c6bbb5d6cbaaa5d2408547fea7b02b",
"de8a940d8a69a64ce264d2ab7320662aef2e391c587cb2aae22a86718d5dffbb",
"94176f1310b26e54d4de48f87b74aa0b60532f184a2268508dece86dd7f85d36",
"9ce6ee3fca56c9256a69df404782301300a6e5e7f5a25a1f6d68c0e9e42584c9",
"7c423c4a220c6ff43ab6432f92b166323c58ee77f8c096ba0b00d52d7bd507e8",
"0b62b9c1ae4d4988720e8d41d980b334458189de0a3dd01699338d7b07c3894e",
"64f45f6f75110624506c53716f2fc1d5fe5f88f82a5bc6a7459ce70eae56dbb3",
"12ffbeb8e52fed161af4d8a015d1a5c45dcb8240e5c8933ce3a88ba2c58f97e8",
"2ee6b7b96043c8ded9fb52f87cdd0d0580ca6f8cef183c8a656394a11c0aa393",
"aaef26b1f5726258bf9ce305a3e54bca65cf68779f90f9d24287245c27362e27",
"ef59588dce57c35d010bea4d209f44c62f0b7c7e65bc0226c0e4971934da9435",
"0e606c2f6f8dcd579faf4739312bd7327ac7796fa44a81780fe0d66fc7761fb9",
"2f307198afdbde5f95989a17e06ce1bb9ff36c441cf3b2248431534fe13bb9fe",
"51418e6df23d450aaacc74ef2df53a6b1693727b70bda9ebc43acfc23d8fb5ea",
"6e9e3ac46705ed80520695b924435b00d2b3079598bf7faca7fd1524be777e5e",
"1e96241e2876aad29ce64f5d7e7fbb8db7265449df816c0d30a96633778c5cb6",
"81788f00eb72696d811f946e65d2c96528c45590874a1defdd46651e9b79a3a1",
"d9aa5a9f1df50e933d7105a5d72b5fe96bfbb9fd4b5b0eaa5e80af12e72d497a",
"e1b6976a732d27fc5d6a96b6d3d0d1d5eaa6ec46bae4665f17e7a43aefc75280",
"9151c75edcec1cc90aa2d2c240ff657b0eef3f5f1ec37418c8854b2493114f1d",
"3e7c12d0132421f08ea0a390cfa325e422a6b35120fb2eb650f108a165237934",
"1ee0e85c7d8a91089c03f37318cdc9127026bf789e3ce4b75046eaa3eebd3458",
"4ae64a3ef66cad847409ce175bd5365c9097fd21647a05730ac6b45841add3c8",
"f0ea0f334cf1d64678a6dab08c07e2f94f339e8389bd17ebc882b5c8b736cbf2",
"da904db96060546ff69e28993ce8183766da9402ac10fae9fc1f1d67ebd83c90",
"db11820615f7b5e47778c45d2e083e77f49b608b587dc09ec26f077aba07a242",
"ff5c726a83bd785484de75bb03b421f9e8e382bf2740120a2fcf72326aa01c75",
"f8643a7efd6304980db323303ab73a6fd4f4ee1047520d39d571580395b97f21",
"8facf9737d07838aedf6030593bfb247d8c29fe8d9b18b2913408627a4424d7e",
"f0672964aa6e4c7dd4768e18827023787386927f4db89fd661444979afb43c18",
"6fd3649c8401f2704ed2be18518b870eb6bf2b9a6689d1b336f05bd8b49017f6",
"ed172dac7de827493e0c0fdd8d3299333acb678e72ed499e0224b389cc1e0fba",
"7f9a8a8cc8e34add11934a1a5882be5978a6d28405cb0a053ec5699a502b1cef",
"6ca829ebd2a0a40994f68c1db7978ec274b45c46e9b351df869a2bfe0630bbd4",
"0bbb017c437573a55db88258a9d9a01188bdd23bb6b26903b137814871661f47",
"9a6358d2541f46b6d05b80fe25a2cb025fbe9e4b227a6275908d5ee31c948569",
"a75d26c6d4ce944024f10e6d23e8b5b888d680120e15dc0e4fee8d8833ee0c6a",
"1d43d33556699b42c124b46e41243abf48727fe488428056fdd174a3861c1e3c",
"7b5bd3fecbaa093f005c4f806ea67846c0df6b04df7729925cb14724f6a8b582",
"6bdf2b54f2f5ab90191261d33dee80fede75896994016422b28db8ba62327d82",
"1a16181b250085a91ccecc118473fa2ab98515e894a7b63b347c24b5be560c7a",
"22d24891755910b48ad632358c26245bdcc375abc41f7e2c9fb3c7773dbf4e22",
"5b70c5d4a373d541619c944fcc3b61259550b0e9fba3eca16f0879e5845b43b9",
"b78f9098c9d76987b7409e63426a8d49972bb4e75289576c680cf96513d44b6d",
"916b53b8e85eb7e0a2a76d6fc8d2163430e7183ccb103d6705f54af4bb070907",
"dc3d78f43110d2aa9df83c5485ec33663ad5452b8cdeb1aeeac9d6b1487fb781",
"3975539ed5402cb9f5ab503584524dd141cc4296b666ec66d807f94f62b1c026",
"bd1f97fd89183643423073f22733880616456ca41960699f18e868cb9ac35508",
"90b468ff0f83460c3dd8cfe778c39d32c6bb1eeff9ac5de7804a4050d3b8073e",
"0e886d49d88b82c9f8dbdd2f38a535992f35ab16629724d746394db3898235fa",
"76c22e965242d1ca5614e829d9028dcad9c4b09393bcbdd318b0365557335fb9",
"59b168488ec8629f820a1efd8fc5a0c2adec4253e61d6a2945a68a9a43be9035",
"ff172b42854eaf2865caa985d2fb6283c5ab19574126623ffd615a761a5bce72",
"cb46ac9ccc024ee74c96e3cf1c13a6949a432e855dfa881b6a307c0e6daac59e",
"9971574924c0f413bf4c0f96bb9c2fbdfea8f475e33a8fb6f15fa40903b63444",
"1a95567deb0f45a8941e2248f33286485984a5e9d86d16c37d42169ad864dc36",
"205fc7f7ec7a83f0bc22d5269c91762cd00adc7428456d799be5a0cd76f08b0f",
"849dd41ef59a722901b7a0deb2c1fd3c110a91a726120a0a119cb7a15cf98438",
"a32880917c714612101af95e5c8d8eb5fb046fdcc68bae76c05b829b3fa73c2e",
"70b38d6d510d13b359dffa910329952c620a4bce4ee7a8552b9bb3a14572394d",
"ef257ab2f4226faa6ba288a6793f026609068effb866c18496a847e8b60b102d",
"e5196ab42ff53c8352288bde6b6b7312cd6f39f7d21b556b0db178d8470d5790",
"ca98f128bf085f2b718f2b3c12da7c4d98887cc94251a2b1705b637611bd83bb",
"79508f0b93a49ec19c5cb05906ca1ba3d3db8ed4f9c6884873d0d7e3e985ea51",
"9088be3f47f9debc63e928739f7163182b49eab044518b151f0b89f6b6aefdd0",
"46b2782fd669b6288a4d7348cf6671360277ba4864cc69bce3497369ac2ec31e",
"0fa5131557db67b430d516530be939ff25882adf68a076602f3dfad8c77c963a",
"3404302cc097d5457244453a4c9990804201ee8161188df811bcb32404998c71",
"856939710dbb90a8eeda875a31f9a52af759bd932b88e7b08df35414c54d4721",
"72569573b9b41d0ac5ce17764a139c6b8b36ef3ca6d92cec625dbcdae758ba22",
"9746da344e435a008d6acb4847211bb676376ecc76c825b5d44a28b89ceeb40e",
"3eafded1595516f032e33ec975f4c9c3a1055d13aa5575cf8a801d6103fdbeb4",
"e88a6d2daa863c0787cc523a2cab45c546fad788951b10d75e2b0954db24cca7",
"38f531e67f88f66de44d3357c8e8f2db456160ca31dd2024c9562f6afd260278",
};
// block 685498 (13 key images in one transaction)
static const char * const key_images_685498[] =
{
"749b7277aa21c70c417f255fb181c3a30b44277edf657eaaebf28a2709dd2a90",
"5a9b3e1a87332d735cedaa2b5623a6a5e99d99f5a2887c8fc84293577e8bf25c",
"bea438768445eb3650cf619bf6758e94035abfe0ccda91d4a58c582df143d835",
"376e237ff4da5e5cbd6e1bba4b01412fa751f2959c0c57006589f382413df429",
"14ac2f2e044f8635a3a42ecb46c575424073c1f6e5ed5e905f516d57f63184b5",
"2d1d2ecb77b69a2901de00897d0509c1b7855a3b2f8eb1afe419008fc03cd15a",
"ea01658f0972b77ae9112d525ec073e3ec5c3b98d5ad912d95ab2636354b70b6",
"d3934864a46101d8c242415282e7fc9ee73ad16cd40355535d226ab45ecdb61a",
"ee379b05c5d02432330ebd4ea9c4f1c87d14c388568d526a0f8a22649a14e453",
"aeb7b842b410b13ca4af7a5ffd5ae6caddc8bfec653df1b945e478839a2e0057",
"451806929d9f5c3a7f365472703871abadc25b2a5a2d75472a45e86cd76c610b",
"272d9b9fcc9e253c08da9caf8233471150019582eaefef461c1f9ceff7e2c337",
"633cdedeb3b96ec4f234c670254c6f721e0b368d00b48c6b26759db7d62cf52d",
};
if (height() > 202612)
{
for (const auto &kis: key_images_202612)
{
crypto::key_image ki;
epee::string_tools::hex_to_pod(kis, ki);
if (!has_key_image(ki))
{
LOG_PRINT_L1("Fixup: adding missing spent key " << ki);
add_spent_key(ki);
}
}
}
if (height() > 685498)
{
for (const auto &kis: key_images_685498)
{
crypto::key_image ki;
epee::string_tools::hex_to_pod(kis, ki);
if (!has_key_image(ki))
{
LOG_PRINT_L1("Fixup: adding missing spent key " << ki);
add_spent_key(ki);
}
}
}
}
batch_stop();
}
bool BlockchainDB::txpool_tx_matches_category(const crypto::hash& tx_hash, relay_category category)
{
try
+91 -23
View File
@@ -1,4 +1,5 @@
// Copyright (c) 2014-2022, The Monero Project
// Copyright (c) 2014-2023, The Monero Project
// Portions Copyright (c) 2023-2024, Salvium (author: SRCG)
//
// All rights reserved.
//
@@ -40,6 +41,7 @@
#include "cryptonote_basic/difficulty.h"
#include "cryptonote_basic/hardfork.h"
#include "cryptonote_protocol/enums.h"
#include "oracle/asset_types.h"
/** \file
* Cryptonote Blockchain Database Interface
@@ -126,6 +128,7 @@ struct output_data_t
crypto::public_key pubkey; //!< the output's public key (for spend verification)
uint64_t unlock_time; //!< the output's unlock time (or height)
uint64_t height; //!< the height of the block which created the output
uint32_t asset_type; //!< the asset type of the output
rct::key commitment; //!< the output's amount commitment (for spend verification)
};
#pragma pack(pop)
@@ -155,13 +158,21 @@ struct txpool_tx_meta_t
{
crypto::hash max_used_block_id;
crypto::hash last_failed_id;
crypto::public_key return_pubkey;
crypto::public_key return_address;
crypto::public_key one_time_public_key;
uint64_t weight;
uint64_t fee;
uint64_t amount_burnt;
uint64_t amount_slippage_limit;
uint64_t max_used_block_height;
uint64_t last_failed_height;
uint64_t receive_time;
uint64_t last_relayed_time; //!< If received over i2p/tor, randomized forward time. If Dandelion++stem, randomized embargo time. Otherwise, last relayed timestamp
// 112 bytes
uint32_t source_asset_id;
uint32_t destination_asset_id;
// 232 bytes
uint8_t tx_type;
uint8_t kept_by_block;
uint8_t relayed;
uint8_t do_not_relay;
@@ -172,7 +183,7 @@ struct txpool_tx_meta_t
uint8_t is_forwarding: 1;
uint8_t bf_padding: 3;
uint8_t padding[76]; // till 192 bytes
uint8_t padding[19]; // till 256 bytes
void set_relay_method(relay_method method) noexcept;
relay_method get_relay_method() const noexcept;
@@ -187,6 +198,14 @@ struct txpool_tx_meta_t
}
};
typedef struct yield_tx_info {
uint64_t block_height;
crypto::hash tx_hash;
uint64_t locked_coins;
crypto::public_key return_address;
crypto::public_key P_change;
crypto::public_key return_pubkey;
} yield_tx_info;
#define DBF_SAFE 1
#define DBF_FAST 2
@@ -398,15 +417,22 @@ private:
* @param cumulative_difficulty the accumulated difficulty after this block
* @param coins_generated the number of coins generated total after this block
* @param blk_hash the hash of the block
* @param slippage_total the total value (expressed in SAL coins) of all slippage for this block
* @param yield_total the total of SAL coins that have been locked for yield in this block
*/
virtual void 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
, const crypto::hash& blk_hash
) = 0;
virtual void 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,
const cryptonote::network_type& nettype,
cryptonote::yield_block_info& ybi
) = 0;
/**
* @brief remove data about the top block
@@ -440,7 +466,7 @@ private:
* @param tx_prunable_hash the hash of the prunable part of the transaction
* @return the transaction ID
*/
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata_ref>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) = 0;
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata_ref>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash, const bool miner_tx) = 0;
/**
* @brief remove data about a transaction
@@ -458,7 +484,7 @@ private:
* @param tx_hash the hash of the transaction to be removed
* @param tx the transaction
*/
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) = 0;
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx, const bool miner_tx) = 0;
/**
* @brief store an output
@@ -486,7 +512,7 @@ private:
* @param commitment the rct commitment to the output amount
* @return amount output index
*/
virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) = 0;
virtual std::pair<uint64_t, uint64_t> add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) = 0;
/**
* @brief store amount output indices for a tx's outputs
@@ -501,7 +527,7 @@ private:
* @param tx_id ID of the transaction containing these outputs
* @param amount_output_indices the amount output indices of the transaction
*/
virtual void add_tx_amount_output_indices(const uint64_t tx_id, const std::vector<uint64_t>& amount_output_indices) = 0;
virtual void add_tx_amount_output_indices(const uint64_t tx_id, const std::vector<std::pair<uint64_t, uint64_t>>& amount_output_indices) = 0;
/**
* @brief store a spent key
@@ -858,6 +884,8 @@ public:
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, const std::vector<std::pair<transaction, blobdata>>& txs
, const cryptonote::network_type& nettype
, cryptonote::yield_block_info& ybi
);
/**
@@ -975,7 +1003,7 @@ public:
*
* @return the cumulative number of rct outputs
*/
virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const = 0;
virtual std::pair<std::vector<uint64_t>, uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights, const std::string asset_type) const = 0;
/**
* @brief fetch the top block's timestamp
@@ -1162,6 +1190,13 @@ public:
*/
virtual uint64_t height() const = 0;
/**
* @brief fetch the circulating supply tally values from the blockchain
*
* @return the current circulating supply tally values
*/
virtual std::map<std::string, uint64_t> get_circulating_supply() const = 0;
/**
* <!--
@@ -1413,6 +1448,19 @@ public:
*/
virtual uint64_t get_num_outputs(const uint64_t& amount) const = 0;
// returns the total number of outputs for asset <asset_type>
/**
* @brief fetches the number of outputs of a given asset type
*
* The subclass should return a count of outputs of the given asset type,
* or zero if there are none.
*
* @param asset_type the asset type to look up
*
* @return the number of outputs of the given asset type
*/
virtual uint64_t get_num_outputs_of_asset_type(const std::string asset_type) const = 0;
/**
* @brief return index of the first element (should be hidden, but isn't)
*
@@ -1438,6 +1486,29 @@ public:
*/
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt = true) const = 0;
/**
* @brief gets output id's using asset type output indices
*
* This function returns a list of global output id's
* using a list of asset type output indices.
*
* @param asset_type
* @param asset_type_output_indices a list of asset type output indices
* @param offsets return-by-reference list of outputs' global id
*/
virtual void get_output_id_from_asset_type_output_index(const std::string asset_type, const std::vector<uint64_t> &asset_type_output_indices, std::vector<uint64_t> &output_indices) const = 0;
/**
* @brief gets output id for an asset type output index
*
* This function returns a global output id
* for a single asset type output index.
*
* @param asset_type
* @param asset_type_output_index asset type output index to retrieve output id for
*/
virtual uint64_t get_output_id_from_asset_type_output_index(const std::string asset_type, const uint64_t &asset_type_output_index) const = 0;
/**
* @brief gets an output's tx hash and index
*
@@ -1511,7 +1582,7 @@ public:
*
* @return a list of amount-specific output indices
*/
virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes = 1) const = 0;
virtual std::vector<std::vector<std::pair<uint64_t, uint64_t>>> get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes = 1) const = 0;
/**
* @brief check if a key image is stored as spent
@@ -1844,13 +1915,10 @@ public:
*/
virtual uint64_t get_database_size() const = 0;
// TODO: this should perhaps be (or call) a series of functions which
// progressively update through version updates
/**
* @brief fix up anything that may be wrong due to past bugs
*/
virtual void fixup();
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) = 0;
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) = 0;
/**
* @brief set whether or not to automatically remove logs
*
File diff suppressed because it is too large Load Diff
+57 -33
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2022, The Monero Project
// Copyright (c) 2014-2023, The Monero Project
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
@@ -53,6 +53,7 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_output_txs;
MDB_cursor *m_txc_output_amounts;
MDB_cursor *m_txc_output_types;
MDB_cursor *m_txc_txs;
MDB_cursor *m_txc_txs_pruned;
@@ -72,6 +73,12 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_hf_versions;
MDB_cursor *m_txc_properties;
MDB_cursor *m_txc_circ_supply;
MDB_cursor *m_txc_circ_supply_tally;
MDB_cursor *m_txc_yield_txs;
MDB_cursor *m_txc_yield_blocks;
} mdb_txn_cursors;
#define m_cur_blocks m_cursors->m_txc_blocks
@@ -79,6 +86,7 @@ typedef struct mdb_txn_cursors
#define m_cur_block_info m_cursors->m_txc_block_info
#define m_cur_output_txs m_cursors->m_txc_output_txs
#define m_cur_output_amounts m_cursors->m_txc_output_amounts
#define m_cur_output_types m_cursors->m_txc_output_types
#define m_cur_txs m_cursors->m_txc_txs
#define m_cur_txs_pruned m_cursors->m_txc_txs_pruned
#define m_cur_txs_prunable m_cursors->m_txc_txs_prunable
@@ -92,6 +100,10 @@ typedef struct mdb_txn_cursors
#define m_cur_alt_blocks m_cursors->m_txc_alt_blocks
#define m_cur_hf_versions m_cursors->m_txc_hf_versions
#define m_cur_properties m_cursors->m_txc_properties
#define m_cur_circ_supply m_cursors->m_txc_circ_supply
#define m_cur_circ_supply_tally m_cursors->m_txc_circ_supply_tally
#define m_cur_yield_txs m_cursors->m_txc_yield_txs
#define m_cur_yield_blocks m_cursors->m_txc_yield_blocks
typedef struct mdb_rflags
{
@@ -101,6 +113,7 @@ typedef struct mdb_rflags
bool m_rf_block_info;
bool m_rf_output_txs;
bool m_rf_output_amounts;
bool m_rf_output_types;
bool m_rf_txs;
bool m_rf_txs_pruned;
bool m_rf_txs_prunable;
@@ -114,6 +127,10 @@ typedef struct mdb_rflags
bool m_rf_alt_blocks;
bool m_rf_hf_versions;
bool m_rf_properties;
bool m_rf_circ_supply;
bool m_rf_circ_supply_tally;
bool m_rf_yield_txs;
bool m_rf_yield_blocks;
} mdb_rflags;
typedef struct mdb_threadinfo
@@ -216,7 +233,7 @@ public:
virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const;
virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const;
virtual std::pair<std::vector<uint64_t>, uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights, const std::string asset_type) const;
virtual uint64_t get_block_timestamp(const uint64_t& height) const;
@@ -250,6 +267,8 @@ public:
virtual uint64_t height() const;
virtual std::map<std::string, uint64_t> get_circulating_supply() const;
virtual bool tx_exists(const crypto::hash& h) const;
virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const;
@@ -269,10 +288,14 @@ public:
virtual uint64_t get_tx_block_height(const crypto::hash& h) const;
virtual uint64_t get_num_outputs(const uint64_t& amount) const;
virtual uint64_t get_num_outputs_of_asset_type(const std::string asset_type) const;
virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const;
virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<output_data_t> &outputs, bool allow_partial = false) const;
virtual void get_output_id_from_asset_type_output_index(const std::string asset_type, const std::vector<uint64_t> &asset_type_output_indices, std::vector<uint64_t> &output_indices) const;
virtual uint64_t get_output_id_from_asset_type_output_index(const std::string asset_type, const uint64_t &asset_type_output_index) const;
virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const;
virtual void get_output_tx_and_index_from_global(const std::vector<uint64_t> &global_indices,
std::vector<tx_out_index> &tx_out_indices) const;
@@ -280,7 +303,7 @@ public:
virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const;
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<tx_out_index> &indices) const;
virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes) const;
virtual std::vector<std::vector<std::pair<uint64_t, uint64_t>>> get_tx_amount_output_indices(const uint64_t tx_id, size_t n_txes) const;
virtual bool has_key_image(const crypto::key_image& img) const;
@@ -318,6 +341,8 @@ public:
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, const std::vector<std::pair<transaction, blobdata>>& txs
, const cryptonote::network_type& nettype
, cryptonote::yield_block_info& ybi
);
virtual void set_batch_transactions(bool batch_transactions);
@@ -365,22 +390,27 @@ private:
void check_and_resize_for_batch(uint64_t batch_num_blocks, uint64_t batch_bytes);
uint64_t get_estimated_batch_size(uint64_t batch_num_blocks, uint64_t batch_bytes) const;
virtual void 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
, const crypto::hash& block_hash
);
virtual void 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,
const cryptonote::network_type& nettype,
cryptonote::yield_block_info& ybi
);
virtual void remove_block();
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata_ref>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash);
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<transaction, blobdata_ref>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash, const bool miner_tx);
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx);
virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx, const bool miner_tx);
virtual uint64_t add_output(const crypto::hash& tx_hash,
virtual std::pair<uint64_t, uint64_t> add_output(const crypto::hash& tx_hash,
const tx_out& tx_output,
const uint64_t& local_index,
const uint64_t unlock_time,
@@ -388,12 +418,12 @@ private:
);
virtual void add_tx_amount_output_indices(const uint64_t tx_id,
const std::vector<uint64_t>& amount_output_indices
const std::vector<std::pair<uint64_t, uint64_t>>& amount_output_indices
);
void remove_tx_outputs(const uint64_t tx_id, const transaction& tx);
void remove_output(const uint64_t amount, const uint64_t& out_index);
void remove_output(const uint64_t amount, const uint64_t& out_index, const std::string& output_asset_type, const uint64_t& asset_type_output_id);
virtual void prune_outputs(uint64_t amount);
@@ -422,29 +452,16 @@ private:
uint64_t get_max_block_size();
void add_max_block_size(uint64_t sz);
// fix up anything that may be wrong due to past bugs
virtual void fixup();
// migrate from older DB version to current
void migrate(const uint32_t oldversion);
// migrate from DB version 0 to 1
void migrate_0_1();
// migrate from DB version 1 to 2
void migrate_1_2();
// migrate from DB version 2 to 3
void migrate_2_3();
// migrate from DB version 3 to 4
void migrate_3_4();
// migrate from DB version 4 to 5
void migrate_4_5();
//void migrate_0_1();
void cleanup_batch();
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi);
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container);
private:
MDB_env* m_env;
@@ -462,6 +479,7 @@ private:
MDB_dbi m_output_txs;
MDB_dbi m_output_amounts;
MDB_dbi m_output_types;
MDB_dbi m_spent_keys;
@@ -475,6 +493,12 @@ private:
MDB_dbi m_properties;
MDB_dbi m_circ_supply;
MDB_dbi m_circ_supply_tally;
MDB_dbi m_yield_txs;
MDB_dbi m_yield_blocks;
mutable uint64_t m_cum_size; // used in batch size estimation
mutable unsigned int m_cum_count;
std::string m_folder;
+9 -9
View File
@@ -157,7 +157,7 @@ endif()
set_property(TARGET blockchain_import
PROPERTY
OUTPUT_NAME "monero-blockchain-import")
OUTPUT_NAME "salvium-blockchain-import")
install(TARGETS blockchain_import DESTINATION bin)
monero_add_executable(blockchain_export
@@ -178,7 +178,7 @@ target_link_libraries(blockchain_export
set_property(TARGET blockchain_export
PROPERTY
OUTPUT_NAME "monero-blockchain-export")
OUTPUT_NAME "salvium-blockchain-export")
install(TARGETS blockchain_export DESTINATION bin)
monero_add_executable(blockchain_blackball
@@ -200,7 +200,7 @@ target_link_libraries(blockchain_blackball
set_property(TARGET blockchain_blackball
PROPERTY
OUTPUT_NAME "monero-blockchain-mark-spent-outputs")
OUTPUT_NAME "salvium-blockchain-mark-spent-outputs")
install(TARGETS blockchain_blackball DESTINATION bin)
@@ -222,7 +222,7 @@ target_link_libraries(blockchain_usage
set_property(TARGET blockchain_usage
PROPERTY
OUTPUT_NAME "monero-blockchain-usage")
OUTPUT_NAME "salvium-blockchain-usage")
install(TARGETS blockchain_usage DESTINATION bin)
monero_add_executable(blockchain_ancestry
@@ -243,7 +243,7 @@ target_link_libraries(blockchain_ancestry
set_property(TARGET blockchain_ancestry
PROPERTY
OUTPUT_NAME "monero-blockchain-ancestry")
OUTPUT_NAME "salvium-blockchain-ancestry")
install(TARGETS blockchain_ancestry DESTINATION bin)
monero_add_executable(blockchain_depth
@@ -264,7 +264,7 @@ target_link_libraries(blockchain_depth
set_property(TARGET blockchain_depth
PROPERTY
OUTPUT_NAME "monero-blockchain-depth")
OUTPUT_NAME "salvium-blockchain-depth")
install(TARGETS blockchain_depth DESTINATION bin)
monero_add_executable(blockchain_stats
@@ -285,7 +285,7 @@ target_link_libraries(blockchain_stats
set_property(TARGET blockchain_stats
PROPERTY
OUTPUT_NAME "monero-blockchain-stats")
OUTPUT_NAME "salvium-blockchain-stats")
install(TARGETS blockchain_stats DESTINATION bin)
monero_add_executable(blockchain_prune_known_spent_data
@@ -307,7 +307,7 @@ target_link_libraries(blockchain_prune_known_spent_data
set_property(TARGET blockchain_prune_known_spent_data
PROPERTY
OUTPUT_NAME "monero-blockchain-prune-known-spent-data")
OUTPUT_NAME "salvium-blockchain-prune-known-spent-data")
install(TARGETS blockchain_prune_known_spent_data DESTINATION bin)
monero_add_executable(blockchain_prune
@@ -316,7 +316,7 @@ monero_add_executable(blockchain_prune
set_property(TARGET blockchain_prune
PROPERTY
OUTPUT_NAME "monero-blockchain-prune")
OUTPUT_NAME "salvium-blockchain-prune")
install(TARGETS blockchain_prune DESTINATION bin)
target_link_libraries(blockchain_prune
+9 -9
View File
@@ -12,16 +12,16 @@ See also each utility's "--help" option.
### Export an existing blockchain database
`$ monero-blockchain-export`
`$ salvium-blockchain-export`
This loads the existing blockchain and exports it to `$MONERO_DATA_DIR/export/blockchain.raw`
### Import the exported file
`$ monero-blockchain-import`
`$ salvium-blockchain-import`
This imports blocks from `$MONERO_DATA_DIR/export/blockchain.raw` (exported using the
`monero-blockchain-export` tool as described above) into the current database.
`salvium-blockchain-export` tool as described above) into the current database.
Defaults: `--batch on`, `--batch size 20000`, `--verify on`
@@ -30,14 +30,14 @@ Batch size refers to number of blocks and can be adjusted for performance based
Verification should only be turned off if importing from a trusted blockchain.
If you encounter an error like "resizing not supported in batch mode", you can just re-run
the `monero-blockchain-import` command again, and it will restart from where it left off.
the `salvium-blockchain-import` command again, and it will restart from where it left off.
```bash
## use default settings to import blockchain.raw into database
$ monero-blockchain-import
$ salvium-blockchain-import
## fast import with large batch size, database mode "fastest", verification off
$ monero-blockchain-import --batch-size 20000 --database lmdb#fastest --verify off
$ salvium-blockchain-import --batch-size 20000 --database lmdb#fastest --verify off
```
@@ -80,9 +80,9 @@ LMDB flags (more than one may be specified):
## Examples:
```bash
$ monero-blockchain-import --database lmdb#fastest
$ salvium-blockchain-import --database lmdb#fastest
$ monero-blockchain-import --database lmdb#nosync
$ salvium-blockchain-import --database lmdb#nosync
$ monero-blockchain-import --database lmdb#nosync,nometasync
$ salvium-blockchain-import --database lmdb#nosync,nometasync
```
@@ -4,16 +4,16 @@ Monero Blockchain Stats utlity exports daily statistics for the monero blockchai
## Usage:
See also the utility's help option. `monero-blockchain-stats --help`
See also the utility's help option. `salvium-blockchain-stats --help`
From the command line run:
`$ monero-blockchain-stats`
`$ salvium-blockchain-stats`
This loads the existing blockchain and prints the results to the terminal. Default printed data includes Blocks per Day, Total Blocks, Transactions per Day, Total Transactions, Bytes per Day and Total Bytes. The format of the output is in tab delimited csv which is printed to the console. Redirecting or piping the output of the command allows for saving the output to a csv file or feeding your own script accordingly, i.e.:
- `monero-blockchain-stats > stats-$(date +'%Y-%m-%d').csv`
- `monero-blockchain-stats | save-to-database.sh`
- `salvium-blockchain-stats > stats-$(date +'%Y-%m-%d').csv`
- `salvium-blockchain-stats | save-to-database.sh`
### Options
`--data-dir arg`
@@ -386,12 +386,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-ancestry.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-ancestry.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
@@ -1176,7 +1176,7 @@ int main(int argc, char* argv[])
const command_line::arg_descriptor<bool> arg_rct_only = {"rct-only", "Only work on ringCT outputs", false};
const command_line::arg_descriptor<bool> arg_check_subsets = {"check-subsets", "Check ring subsets (very expensive)", false};
const command_line::arg_descriptor<bool> arg_verbose = {"verbose", "Verbose output)", false};
const command_line::arg_descriptor<std::vector<std::string> > arg_inputs = {"inputs", "Path to Monero DB, and path to any fork DBs"};
const command_line::arg_descriptor<std::vector<std::string> > arg_inputs = {"inputs", "Path to Salvium DB, and path to any fork DBs"};
const command_line::arg_descriptor<std::string> arg_db_sync_mode = {
"db-sync-mode"
, "Specify sync option, using format [safe|fast|fastest]:[nrecords_per_sync]."
@@ -1219,12 +1219,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-mark-spent-outputs.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-mark-spent-outputs.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
@@ -88,12 +88,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-depth.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-depth.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
@@ -90,12 +90,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-export.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-export.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
@@ -487,8 +487,9 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
try
{
cryptonote::yield_block_info ybi; // This just gets discarded because we aren't looking to maintain a cache of YBI data in the import utility
uint64_t long_term_block_weight = core.get_blockchain_storage().get_next_long_term_block_weight(block_weight);
core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs);
core.get_blockchain_storage().get_db().add_block(std::make_pair(b, block_to_blob(b)), block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, ybi);
}
catch (const std::exception& e)
{
@@ -637,7 +638,7 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
@@ -674,7 +675,7 @@ int main(int argc, char* argv[])
}
m_config_folder = command_line::get_arg(vm, cryptonote::arg_data_dir);
mlog_configure(mlog_get_default_log_path("monero-blockchain-import.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-import.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
@@ -483,12 +483,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-prune.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-prune.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
@@ -137,12 +137,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-prune-known-spent-data.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-prune-known-spent-data.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
@@ -175,12 +175,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-stats.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-stats.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
@@ -242,7 +242,7 @@ int main(int argc, char* argv[])
/*
* The default output can be plotted with GnuPlot using these commands:
set key autotitle columnhead
set title "Monero Blockchain Growth"
set title "Salvium Blockchain Growth"
set timefmt "%Y-%m-%d"
set xdata time
set xrange ["2014-04-17":*]
@@ -120,12 +120,12 @@ int main(int argc, char* argv[])
if (command_line::get_arg(vm, command_line::arg_help))
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << "Salvium '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
std::cout << desc_options << std::endl;
return 1;
}
mlog_configure(mlog_get_default_log_path("monero-blockchain-usage.log"), true);
mlog_configure(mlog_get_default_log_path("salvium-blockchain-usage.log"), true);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
Binary file not shown.
+5
View File
@@ -245,6 +245,11 @@ namespace cryptonote
ADD_CHECKPOINT2(2720000, "b19fb41dff15bd1016afbee9f8469f05aab715c9e5d1b974466a11fd58ecbb86", "0x3216b5851ddbb61");
ADD_CHECKPOINT2(2817000, "39726d19ccaac01d150bec827b877ffae710b516bd633503662036ef4422e577", "0x3900669561954c1");
ADD_CHECKPOINT2(2844000, "28fc7b446dfef5b469f5778eb72ddf32a307a5f5a9823d1c394e772349e05d40", "0x3af384ec0e97d12");
ADD_CHECKPOINT2(2851000, "5bf0e47fc782263191a33f63a67db6c711781dc2a3c442e17ed901ec401be5c9", "0x3b6cd8a8ed610e8");
ADD_CHECKPOINT2(2971000, "3d4cac5ac515eeabd18769ab943af85f36db51d28720def0d0e6effc2c8f5ce3", "0x436e532738b8b5b");
ADD_CHECKPOINT2(2985000, "08f5e6b7301c1b6ed88268a28f8677a06e8ff943b3f9e48d3080f71f9c134bfb", "0x444b7b42a633c96");
ADD_CHECKPOINT2(3088000, "bddf8ca09110d33d6d497f13a113630c2b6af1c84d4f3a6f35cb1446f2604ade", "0x4aed3615c2f8c3e");
ADD_CHECKPOINT2(3102800, "083f4a34f9490403b564286e7f13fd1ed45c52c86fa47195f151594e5bc87504", "0x4bbed52d4da5dfb");
return true;
}
+2 -1
View File
@@ -110,7 +110,8 @@ namespace tools
catch(...)
{
// if failed, try reading in unportable mode
boost::filesystem::copy_file(file_path, file_path + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
//boost::filesystem::copy_file(file_path, file_path + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
tools::copy_file(file_path, file_path + ".unportable");
data_file.close();
data_file.open( file_path, std::ios_base::binary | std::ios_base::in);
if(data_file.fail())
+1
View File
@@ -34,6 +34,7 @@
#include <iostream>
#include <vector>
#include <stdexcept>
#include <cstdint>
namespace tools {
+170
View File
@@ -0,0 +1,170 @@
// Copyright (c) 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.
// Miscellaneous container helpers.
#pragma once
//local headers
//third party headers
//standard headers
#include <algorithm>
#include <unordered_map>
#include <utility>
//forward declarations
namespace tools
{
/// convert an arbitrary function to functor
template <typename F>
inline auto as_functor(F f)
{
return [f = std::move(f)](auto&&... args) { return f(std::forward<decltype(args)>(args)...); };
}
/// convert a binary comparison function to a functor
/// note: for most use-cases 'const T&' will work because only non-trivial types need a user-defined comparison operation
template <typename T, typename ComparisonOpT = bool(const T&, const T&)>
inline auto compare_func(ComparisonOpT comparison_op_func)
{
static_assert(
std::is_same<
bool,
decltype(
comparison_op_func(
std::declval<std::remove_cv_t<T>>(),
std::declval<std::remove_cv_t<T>>()
)
)
>::value,
"invalid callable - expected callable in form bool(T, T)"
);
return as_functor(std::move(comparison_op_func));
}
/// test if a container is sorted and unique according to a comparison criteria (defaults to operator<)
/// NOTE: ComparisonOpT must establish 'strict weak ordering' https://en.cppreference.com/w/cpp/named_req/Compare
template <typename T, typename ComparisonOpT = std::less<typename T::value_type>>
bool is_sorted_and_unique(const T &container, ComparisonOpT comparison_op = ComparisonOpT{})
{
using ValueT = typename T::value_type;
static_assert(
std::is_same<
bool,
decltype(
comparison_op(
std::declval<std::remove_cv_t<ValueT>>(),
std::declval<std::remove_cv_t<ValueT>>()
)
)
>::value,
"invalid callable - expected callable in form bool(ValueT, ValueT)"
);
if (!std::is_sorted(container.begin(), container.end(), comparison_op))
return false;
if (std::adjacent_find(container.begin(),
container.end(),
[comparison_op = std::move(comparison_op)](const ValueT &a, const ValueT &b) -> bool
{
return !comparison_op(a, b) && !comparison_op(b, a);
})
!= container.end())
return false;
return true;
}
/// specialization for raw function pointers
template <typename T>
bool is_sorted_and_unique(const T &container,
bool (*const comparison_op_func)(const typename T::value_type&, const typename T::value_type&))
{
return is_sorted_and_unique(container, compare_func<typename T::value_type>(comparison_op_func));
}
/// convenience wrapper for checking if the key to a mapped object is correct for that object
/// example: std::unorderd_map<rct::key, std::pair<rct::key, rct::xmr_amount>> where the map key is supposed to
/// reproduce the pair's rct::key; use the predicate to check that relationship
template <typename KeyT, typename ValueT, typename PredT>
bool keys_match_internal_values(const std::unordered_map<KeyT, ValueT> &map, PredT check_key_func)
{
static_assert(
std::is_same<
bool,
decltype(
check_key_func(
std::declval<std::remove_cv_t<KeyT>>(),
std::declval<std::remove_cv_t<ValueT>>()
)
)
>::value,
"invalid callable - expected callable in form bool(KeyT, ValueT)"
);
for (const auto &map_element : map)
{
if (!check_key_func(map_element.first, map_element.second))
return false;
}
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)
{
using MapValueT = typename std::unordered_map<KeyT, ValueT>::value_type;
static_assert(
std::is_same<
bool,
decltype(predicate(std::declval<std::remove_cv_t<MapValueT>>()))
>::value,
"invalid callable - expected callable in form bool(Value)"
);
for (auto map_it = map_inout.begin(); map_it != map_inout.end();)
{
if (predicate(*map_it))
map_it = map_inout.erase(map_it);
else
++map_it;
}
}
} //namespace tools
+1 -1
View File
@@ -62,7 +62,7 @@ namespace tools
while (1)
{
t1 = epee::misc_utils::get_ns_count();
if (t1 - t0 > 1*1000000000) break; // work one second
if (t1 - t0 > 1*100000000) break; // work 0.1 seconds
}
uint64_t r1 = get_tick_count();
+2 -2
View File
@@ -102,11 +102,11 @@ namespace tools
std::string get_update_url(const std::string &software, const std::string &subdir, const std::string &buildtag, const std::string &version, bool user)
{
const char *base = user ? "https://downloads.getmonero.org/" : "https://updates.getmonero.org/";
const char *base = user ? "https://downloads.salvium.network/" : "https://updates.salvium.network/";
#ifdef _WIN32
static const char *extension = strncmp(buildtag.c_str(), "source", 6) ? (strncmp(buildtag.c_str(), "install-", 8) ? ".zip" : ".exe") : ".tar.bz2";
#elif defined(__APPLE__)
static const char *extension = strncmp(software.c_str(), "monero-gui", 10) ? ".tar.bz2" : ".dmg";
static const char *extension = strncmp(software.c_str(), "salvium-gui", 10) ? ".tar.bz2" : ".dmg";
#else
static const char extension[] = ".tar.bz2";
#endif
+33 -20
View File
@@ -115,6 +115,24 @@ static int flock_exnb(int fd)
namespace tools
{
void copy_file(const std::string& from, const std::string& to)
{
using boost::filesystem::path;
#if BOOST_VERSION < 107400
// Remove this preprocessor if/else when we are bumping the boost version.
boost::filesystem::copy_file(
path(from),
path(to),
boost::filesystem::copy_option::overwrite_if_exists);
#else
boost::filesystem::copy_file(
path(from),
path(to),
boost::filesystem::copy_options::overwrite_existing);
#endif
}
std::function<void(int)> signal_handler::m_handler;
private_file::private_file() noexcept : m_handle(), m_filename() {}
@@ -882,13 +900,6 @@ std::string get_nix_version_display_string()
bool is_local_address(const std::string &address)
{
// always assume Tor/I2P addresses to be untrusted by default
if (is_privacy_preserving_network(address))
{
MDEBUG("Address '" << address << "' is Tor/I2P, non local");
return false;
}
// extract host
epee::net_utils::http::url_content u_c;
if (!epee::net_utils::parse_url(address, u_c))
@@ -902,20 +913,22 @@ std::string get_nix_version_display_string()
return false;
}
// resolve to IP
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query(u_c.host, "");
boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query);
while (i != boost::asio::ip::tcp::resolver::iterator())
if (u_c.host == "localhost" || boost::ends_with(u_c.host, ".localhost")) { // RFC 6761 (6.3)
MDEBUG("Address '" << address << "' is local");
return true;
}
boost::system::error_code ec;
const auto parsed_ip = boost::asio::ip::address::from_string(u_c.host, ec);
if (ec) {
MDEBUG("Failed to parse '" << address << "' as IP address: " << ec.message() << ". Considering it not local");
return false;
}
if (parsed_ip.is_loopback())
{
const boost::asio::ip::tcp::endpoint &ep = *i;
if (ep.address().is_loopback())
{
MDEBUG("Address '" << address << "' is local");
return true;
}
++i;
MDEBUG("Address '" << address << "' is local");
return true;
}
MDEBUG("Address '" << address << "' is not local");
+2
View File
@@ -67,6 +67,8 @@ namespace tools
}
};
void copy_file(const std::string& from, const std::string& to);
//! A file restricted to process owner AND process. Deletes file on destruction.
class private_file {
std::unique_ptr<std::FILE, close_file> m_handle;
+167
View File
@@ -0,0 +1,167 @@
// Copyright (c) 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.
// Variant wrapper class.
#pragma once
//local headers
//third party headers
#include <boost/blank.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/distance.hpp>
#include <boost/mpl/find.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/none_t.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/get.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant.hpp>
//standard headers
#include <stdexcept>
#include <type_traits>
#include <utility>
//forward declarations
namespace tools
{
[[noreturn]] inline void variant_static_visitor_blank_err()
{ throw std::runtime_error("variant: tried to visit an empty variant."); }
[[noreturn]] inline void variant_unwrap_err()
{ throw std::runtime_error("variant: tried to access value of incorrect type."); }
////
// variant: convenience wrapper around boost::variant with a cleaner interface
// - the variant is 'optional' - an empty variant will evaluate to 'false' and an initialized variant will be 'true'
///
template <typename ResultT>
struct variant_static_visitor : public boost::static_visitor<ResultT>
{
/// provide visitation for empty variants
/// - add this to your visitor with: using variant_static_visitor::operator();
[[noreturn]] ResultT operator()(const boost::blank) { variant_static_visitor_blank_err(); }
[[noreturn]] ResultT operator()(const boost::blank) const { variant_static_visitor_blank_err(); }
};
template <typename... Types>
class variant final
{
using VType = boost::variant<boost::blank, Types...>;
public:
//constructors
/// default constructor
variant() = default;
variant(boost::none_t) : variant{} {} //act like boost::optional
/// construct from variant type (use enable_if to avoid issues with copy/move constructor)
template <typename T,
typename std::enable_if<
!std::is_same<
std::remove_cv_t<std::remove_reference_t<T>>,
variant<Types...>
>::value,
bool
>::type = true>
variant(T &&value) : m_value{std::forward<T>(value)} {}
//overloaded operators
/// boolean operator: true if the variant isn't empty/uninitialized
explicit operator bool() const noexcept { return !this->is_empty(); }
//member functions
/// check if empty/uninitialized
bool is_empty() const noexcept { return m_value.which() == 0; }
/// check the variant type
template <typename T>
bool is_type() const noexcept { return this->index() == this->type_index_of<T>(); }
/// try to get a handle to the embedded value (return nullptr on failure)
template <typename T>
T* try_unwrap() noexcept { return boost::strict_get< T>(&m_value); }
template <typename T>
const T* try_unwrap() const noexcept { return boost::strict_get<const T>(&m_value); }
/// get a handle to the embedded value
template <typename T>
T& unwrap()
{
T *value_ptr{this->try_unwrap<T>()};
if (!value_ptr) variant_unwrap_err();
return *value_ptr;
}
template <typename T>
const T& unwrap() const
{
const T *value_ptr{this->try_unwrap<T>()};
if (!value_ptr) variant_unwrap_err();
return *value_ptr;
}
/// get the type index of the currently stored type
int index() const noexcept { return m_value.which(); }
/// get the type index of a requested type (compile error for invalid types) (boost::mp11 is boost 1.66.0)
template <typename T>
static constexpr int type_index_of() noexcept
{
using types = boost::mpl::vector<boost::blank, Types...>;
using elem = typename boost::mpl::find<types, T>::type;
using begin = typename boost::mpl::begin<types>::type;
return boost::mpl::distance<begin, elem>::value;
}
/// check if two variants have the same type
static bool same_type(const variant<Types...> &v1, const variant<Types...> &v2) noexcept
{ return v1.index() == v2.index(); }
/// apply a visitor to the variant
template <typename VisitorT>
typename VisitorT::result_type visit(VisitorT &&visitor)
{
return boost::apply_visitor(std::forward<VisitorT>(visitor), m_value);
}
template <typename VisitorT>
typename VisitorT::result_type visit(VisitorT &&visitor) const
{
return boost::apply_visitor(std::forward<VisitorT>(visitor), m_value);
}
private:
//member variables
/// variant of all value types
VType m_value;
};
} //namespace tools
+6 -4
View File
@@ -42,10 +42,11 @@
#define CTHR_RWLOCK_TRYLOCK_READ(x) TryAcquireSRWLockShared(&x)
#define CTHR_THREAD_TYPE HANDLE
#define CTHR_THREAD_RTYPE void
#define CTHR_THREAD_RETURN return
#define CTHR_THREAD_CREATE(thr, func, arg) ((thr = (HANDLE)_beginthread(func, 0, arg)) != -1L)
#define CTHR_THREAD_JOIN(thr) WaitForSingleObject((HANDLE)thr, INFINITE)
#define CTHR_THREAD_RTYPE unsigned __stdcall
#define CTHR_THREAD_RETURN _endthreadex(0); return 0;
#define CTHR_THREAD_CREATE(thr, func, arg) ((thr = (HANDLE)_beginthreadex(0, 0, func, arg, 0, 0)) != 0L)
#define CTHR_THREAD_JOIN(thr) do { WaitForSingleObject(thr, INFINITE); CloseHandle(thr); } while(0)
#define CTHR_THREAD_CLOSE(thr) CloseHandle((HANDLE)thr);
#else
@@ -64,5 +65,6 @@
#define CTHR_THREAD_RETURN return NULL
#define CTHR_THREAD_CREATE(thr, func, arg) (pthread_create(&thr, NULL, func, arg) == 0)
#define CTHR_THREAD_JOIN(thr) pthread_join(thr, NULL)
#define CTHR_THREAD_CLOSE(thr)
#endif
+186
View File
@@ -0,0 +1,186 @@
// Copyright (c) 2022, The Monero Project
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "generators.h"
#include "crypto.h"
extern "C"
{
#include "crypto-ops.h"
}
#include "hash.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <mutex>
namespace crypto
{
/// constexpr assert for old gcc bug: https://stackoverflow.com/questions/34280729/throw-in-constexpr-function
/// - this function won't compile in a constexpr context if b == false
constexpr void constexpr_assert(const bool b) { b ? 0 : throw std::runtime_error("constexpr assert failed"); };
/// constexpr paste bytes into an array-of-bytes type
template<typename T>
constexpr T bytes_to(const std::initializer_list<unsigned char> bytes)
{
T out{}; // zero-initialize trailing bytes
auto current = std::begin(out.data);
constexpr_assert(static_cast<long>(bytes.size()) <= std::end(out.data) - current);
for (const unsigned char byte : bytes)
*current++ = byte;
return out;
}
// generators
//standard ed25519 generator G: {x, 4/5} (positive x when decompressing y = 4/5)
constexpr public_key G = bytes_to<public_key>({ 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66 });
//pedersen commitment generator H: toPoint(cn_fast_hash(G))
constexpr public_key H = bytes_to<public_key>({ 0x8b, 0x65, 0x59, 0x70, 0x15, 0x37, 0x99, 0xaf, 0x2a, 0xea, 0xdc, 0x9f, 0xf1,
0xad, 0xd0, 0xea, 0x6c, 0x72, 0x51, 0xd5, 0x41, 0x54, 0xcf, 0xa9, 0x2c, 0x17, 0x3a, 0x0d, 0xd3, 0x9c, 0x1f, 0x94 });
static ge_p3 G_p3;
static ge_p3 H_p3;
static ge_cached G_cached;
static ge_cached H_cached;
// misc
static std::once_flag init_gens_once_flag;
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static public_key reproduce_generator_G()
{
// G = {x, 4/5 mod q}
fe four, five, inv_five, y;
fe_0(four);
fe_0(five);
four[0] = 4;
five[0] = 5;
fe_invert(inv_five, five);
fe_mul(y, four, inv_five);
public_key reproduced_G;
fe_tobytes(to_bytes(reproduced_G), y);
return reproduced_G;
}
//-------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------
static public_key reproduce_generator_H()
{
// H = 8*to_point(keccak(G))
// note: this does not use the point_from_bytes() function found in H_p(), instead directly interpreting the
// input bytes as a compressed point (this can fail, so should not be used generically)
// note2: to_point(keccak(G)) is known to succeed for the canonical value of G (it will fail 7/8ths of the time
// normally)
ge_p3 temp_p3;
ge_p2 temp_p2;
ge_p1p1 temp_p1p1;
hash H_temp_hash{cn_fast_hash(to_bytes(G), sizeof(ec_point))};
(void)H_temp_hash; //suppress unused warning
assert(ge_frombytes_vartime(&temp_p3, reinterpret_cast<const unsigned char*>(&H_temp_hash)) == 0);
ge_p3_to_p2(&temp_p2, &temp_p3);
ge_mul8(&temp_p1p1, &temp_p2);
ge_p1p1_to_p3(&temp_p3, &temp_p1p1);
public_key reproduced_H;
ge_p3_tobytes(to_bytes(reproduced_H), &temp_p3);
return reproduced_H;
}
//-------------------------------------------------------------------------------------------------------------------
// Make generators, but only once
//-------------------------------------------------------------------------------------------------------------------
static void init_gens()
{
std::call_once(init_gens_once_flag,
[&](){
// sanity check the generators
static_assert(static_cast<unsigned char>(G.data[0]) == 0x58, "compile-time constant sanity check");
static_assert(static_cast<unsigned char>(H.data[0]) == 0x8b, "compile-time constant sanity check");
// build ge_p3 representations of generators
const int G_deserialize = ge_frombytes_vartime(&G_p3, to_bytes(G));
const int H_deserialize = ge_frombytes_vartime(&H_p3, to_bytes(H));
(void)G_deserialize; assert(G_deserialize == 0);
(void)H_deserialize; assert(H_deserialize == 0);
// get cached versions
ge_p3_to_cached(&G_cached, &G_p3);
ge_p3_to_cached(&H_cached, &H_p3);
// in debug mode, check that generators are reproducible
(void)reproduce_generator_G; assert(reproduce_generator_G() == G);
(void)reproduce_generator_H; assert(reproduce_generator_H() == H);
});
}
//-------------------------------------------------------------------------------------------------------------------
public_key get_G()
{
return G;
}
//-------------------------------------------------------------------------------------------------------------------
public_key get_H()
{
return H;
}
//-------------------------------------------------------------------------------------------------------------------
ge_p3 get_G_p3()
{
init_gens();
return G_p3;
}
//-------------------------------------------------------------------------------------------------------------------
ge_p3 get_H_p3()
{
init_gens();
return H_p3;
}
//-------------------------------------------------------------------------------------------------------------------
ge_cached get_G_cached()
{
init_gens();
return G_cached;
}
//-------------------------------------------------------------------------------------------------------------------
ge_cached get_H_cached()
{
init_gens();
return H_cached;
}
//-------------------------------------------------------------------------------------------------------------------
} //namespace crypto
+47
View File
@@ -0,0 +1,47 @@
// Copyright (c) 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.
#pragma once
extern "C"
{
#include "crypto-ops.h"
}
#include "crypto.h"
namespace crypto
{
public_key get_G();
public_key get_H();
ge_p3 get_G_p3();
ge_p3 get_H_p3();
ge_cached get_G_cached();
ge_cached get_H_cached();
} //namespace crypto
+13 -4
View File
@@ -34,7 +34,7 @@ typedef struct {
unsigned long long databitlen; /*the message size in bits*/
unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/
DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/
unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/
DATA_ALIGN16(unsigned char buffer[64]); /*the 512-bit message block to be hashed;*/
} hashState;
@@ -213,16 +213,24 @@ static void E8(hashState *state)
/*The compression function F8 */
static void F8(hashState *state)
{
uint64 i;
uint64_t* x = (uint64_t*)state->x;
/*xor the 512-bit message with the fist half of the 1024-bit hash state*/
for (i = 0; i < 8; i++) state->x[i >> 1][i & 1] ^= ((uint64*)state->buffer)[i];
for (int i = 0; i < 8; ++i) {
uint64 b;
memcpy(&b, &state->buffer[i << 3], sizeof(b));
x[i] ^= b;
}
/*the bijective function E8 */
E8(state);
/*xor the 512-bit message with the second half of the 1024-bit hash state*/
for (i = 0; i < 8; i++) state->x[(8+i) >> 1][(8+i) & 1] ^= ((uint64*)state->buffer)[i];
for (int i = 0; i < 8; ++i) {
uint64 b;
memcpy(&b, &state->buffer[i << 3], sizeof(b));
x[i + 8] ^= b;
}
}
/*before hashing a message, initialize the hash state as H0 */
@@ -240,6 +248,7 @@ static HashReturn Init(hashState *state, int hashbitlen)
case 224: memcpy(state->x,JH224_H0,128); break;
case 256: memcpy(state->x,JH256_H0,128); break;
case 384: memcpy(state->x,JH384_H0,128); break;
default:
case 512: memcpy(state->x,JH512_H0,128); break;
}
+2 -1
View File
@@ -332,7 +332,7 @@ static void rx_init_dataset(size_t max_threads) {
local_abort("Couldn't start RandomX seed thread");
}
}
rx_seedthread(&si[n1]);
randomx_init_dataset(main_dataset, si[n1].si_cache, si[n1].si_start, si[n1].si_count);
for (size_t i = 0; i < n1; ++i) CTHR_THREAD_JOIN(st[i]);
CTHR_RWLOCK_UNLOCK_READ(main_cache_lock);
@@ -402,6 +402,7 @@ void rx_set_main_seedhash(const char *seedhash, size_t max_dataset_init_threads)
if (!CTHR_THREAD_CREATE(t, rx_set_main_seedhash_thread, info)) {
local_abort("Couldn't start RandomX seed thread");
}
CTHR_THREAD_CLOSE(t);
}
void rx_slow_hash(const char *seedhash, const void *data, size_t length, char *result_hash) {
+1
View File
@@ -71,6 +71,7 @@ target_link_libraries(cryptonote_basic
checkpoints
cryptonote_format_utils_basic
device
oracle
${Boost_DATE_TIME_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SERIALIZATION_LIBRARY}
+143 -4
View File
@@ -1,4 +1,5 @@
// Copyright (c) 2014-2022, The Monero Project
// Portions Copyright (c) 2023-2024, Salvium (author: SRCG)
//
// All rights reserved.
//
@@ -43,6 +44,7 @@
#include "serialization/debug_archive.h"
#include "serialization/crypto.h"
#include "serialization/keyvalue_serialization.h" // eepe named serialization
#include "serialization/string.h"
#include "cryptonote_config.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
@@ -50,6 +52,8 @@
#include "ringct/rctTypes.h"
#include "device/device.hpp"
#include "cryptonote_basic/fwd.h"
#include "cryptonote_protocol/enums.h"
#include "oracle/pricing_record.h"
namespace cryptonote
{
@@ -79,19 +83,32 @@ namespace cryptonote
{
txout_to_key() { }
txout_to_key(const crypto::public_key &_key) : key(_key) { }
txout_to_key(const crypto::public_key &_key, const std::string &_asset_type, const uint64_t _unlock_time) : key(_key), asset_type(_asset_type), unlock_time(_unlock_time) { }
crypto::public_key key;
std::string asset_type;
uint64_t unlock_time;
BEGIN_SERIALIZE_OBJECT()
FIELD(key)
FIELD(asset_type)
FIELD(unlock_time)
END_SERIALIZE()
};
// outputs >= HF_VERSION_VIEW_TAGS
struct txout_to_tagged_key
{
txout_to_tagged_key() { }
txout_to_tagged_key(const crypto::public_key &_key, const crypto::view_tag &_view_tag) : key(_key), view_tag(_view_tag) { }
txout_to_tagged_key(const crypto::public_key &_key, const std::string &_asset_type, const uint64_t _unlock_time, const crypto::view_tag &_view_tag) : key(_key), asset_type(_asset_type), unlock_time(_unlock_time), view_tag(_view_tag) { }
crypto::public_key key;
std::string asset_type;
uint64_t unlock_time;
crypto::view_tag view_tag; // optimization to reduce scanning time
BEGIN_SERIALIZE_OBJECT()
FIELD(key)
FIELD(asset_type)
VARINT_FIELD(unlock_time)
FIELD(view_tag)
END_SERIALIZE()
};
@@ -138,11 +155,13 @@ namespace cryptonote
struct txin_to_key
{
uint64_t amount;
std::string asset_type;
std::vector<uint64_t> key_offsets;
crypto::key_image k_image; // double spending protection
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(amount)
FIELD(asset_type)
FIELD(key_offsets)
FIELD(k_image)
END_SERIALIZE()
@@ -179,6 +198,20 @@ namespace cryptonote
std::vector<tx_out> vout;
//extra
std::vector<uint8_t> extra;
// TX type
cryptonote::transaction_type type;
// Return address
crypto::public_key return_address;
// Return TX public key
crypto::public_key return_pubkey;
// Source asset type
std::string source_asset_type;
// Destination asset type (this is only necessary for CONVERT transactions)
std::string destination_asset_type;
// Circulating supply information
uint64_t amount_burnt;
// Slippage limit
uint64_t amount_slippage_limit;
BEGIN_SERIALIZE()
VARINT_FIELD(version)
@@ -187,6 +220,17 @@ namespace cryptonote
FIELD(vin)
FIELD(vout)
FIELD(extra)
VARINT_FIELD(type)
if (type != cryptonote::transaction_type::PROTOCOL) {
VARINT_FIELD(amount_burnt)
if (type != cryptonote::transaction_type::MINER) {
FIELD(return_address)
FIELD(return_pubkey)
FIELD(source_asset_type)
FIELD(destination_asset_type)
VARINT_FIELD(amount_slippage_limit)
}
}
END_SERIALIZE()
public:
@@ -198,6 +242,13 @@ namespace cryptonote
vin.clear();
vout.clear();
extra.clear();
type = cryptonote::transaction_type::UNSET;
return_address = crypto::null_pkey;
return_pubkey = crypto::null_pkey;
source_asset_type.clear();
destination_asset_type.clear();
amount_burnt = 0;
amount_slippage_limit = 0;
}
};
@@ -449,6 +500,21 @@ namespace cryptonote
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
}
struct yield_block_info {
uint64_t block_height;
uint64_t slippage_total_this_block;
uint64_t locked_coins_this_block;
uint64_t locked_coins_tally;
uint8_t network_health_percentage;
BEGIN_SERIALIZE()
VARINT_FIELD(block_height)
VARINT_FIELD(slippage_total_this_block)
VARINT_FIELD(locked_coins_this_block)
VARINT_FIELD(locked_coins_tally)
VARINT_FIELD(network_health_percentage)
END_SERIALIZE()
};
/************************************************************************/
@@ -461,6 +527,7 @@ namespace cryptonote
uint64_t timestamp;
crypto::hash prev_id;
uint32_t nonce;
oracle::pricing_record pricing_record;
BEGIN_SERIALIZE()
VARINT_FIELD(major_version)
@@ -468,6 +535,8 @@ namespace cryptonote
VARINT_FIELD(timestamp)
FIELD(prev_id)
FIELD(nonce)
if (major_version >= HF_VERSION_ENABLE_ORACLE)
FIELD(pricing_record)
END_SERIALIZE()
};
@@ -479,14 +548,66 @@ namespace cryptonote
public:
block(): block_header(), hash_valid(false) {}
block(const block &b): block_header(b), hash_valid(false), miner_tx(b.miner_tx), tx_hashes(b.tx_hashes) { if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } }
block &operator=(const block &b) { block_header::operator=(b); hash_valid = false; miner_tx = b.miner_tx; tx_hashes = b.tx_hashes; if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } return *this; }
block(const block &b): block_header(b), hash_valid(false), miner_tx(b.miner_tx), protocol_tx(b.protocol_tx), tx_hashes(b.tx_hashes) { if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } }
block &operator=(const block &b) { block_header::operator=(b); hash_valid = false; miner_tx = b.miner_tx; protocol_tx = b.protocol_tx; tx_hashes = b.tx_hashes; if (b.is_hash_valid()) { hash = b.hash; set_hash_valid(true); } return *this; }
void invalidate_hashes() { set_hash_valid(false); }
bool is_hash_valid() const { return hash_valid.load(std::memory_order_acquire); }
void set_hash_valid(bool v) const { hash_valid.store(v,std::memory_order_release); }
void set_hash(const crypto::hash &h) const { hash = h; set_hash_valid(true); }
transaction miner_tx;
/**
* Ok, the "protocol_tx" is a large part of what makes Salvium unique, and requires a bit of explaining...
*
* In Haven, and therefore Zephyr also, conversions take place "in-transaction". That is to say,
* amounts of coin A are burnt, and amounts of coin B are minted, and the conversion rate is known,
* and therefore verifiable all in the same TX. All very neat and tidy.
*
* But to implement slippage and yield, it isn't quite as easy to put a nice neat bow around it all.
* Solving slippage in particular requires an approach that means it isn't POSSIBLE to know how much
* you are going to receive ahead of the transaction being included in a mined block. The reason for
* this is simple enough to explain... so here goes.
*
* There are an indeterminate number of conversion TXs that may be included in any given block. Each
* of these conversion TXs may improve the relative pool ratio for each other conversion TX, or it
* may worsen it. For example, an "offshore" (to borrow the Haven definition for the sake of expediency)
* increases the stablecoin pool size and reduces the volatile coin pool size. This means that, for
* other "offshore" TXs in the same block, the pool ratios are potentially worsened. Conversely, any
* "onshore" TXs in the same block would experience a balancing effect from the "offshore" TXs in terms
* of the source -> dest asset pool MCAP ratios.
*
* Now, the slippage for a given conversion TX is determined by the following factors:
*
* change in source asset pool MCAP
* change in destination asset pool MCAP
* the source -> dest asset pool ratios
* the amounts that are being burnt / minted
*
* Therefore, it follows that slippage can only accurately be assessed when we know ALL of the changes
* to the above parameters that will occur at a given point in time (specifically, when the block is
* mined). There is a fundamental interdependence between each conversion TX in a given block. This
* means that, in Salvium, you can't tell in advance precisely how much you will get minted by a given
* conversion TX until the block is mined. Instead, when creating a conversion TX, the user is asked
* to specify a minimum amount they will accept - if the transaction can satisfy that criterion when
* it is mined, the conversion will be processed and the minted amount will be sent to the user. If
* the transaction cannot satisfy the minimum minted requirement, the user will be refunded their
* money, minus a nominal transaction fee.
*
* Welcome to Salvium, and the protocol_tx.
* --------------------------------------
* The protocol_tx is a per-block TX (much like the miner_tx, where the block reward gets paid out).
* It is created at the time of populating the block template to be sent to the miner. Specifically,
* the code takes a snapshot of the circulating supply for each asset type, and then applies the
* "amount burnt" for each of the conversion TXs being included in the block. With this updated
* supply tally information, the slippage for each transaction can be calculated and can be tested
* against the "minimum minted" parameter supplied by the user. Transactions that cannot be satisfied
* are refunded using an RCT output in the protocol_tx for the "amount burnt" minus the nominal TX fee.
* The remainder of the conversion TXs will then have an RCT output created in the protocol_tx for the
* converted amount minus the slippage.
*
* The protocol_tx is also used to pay out "yield" amounts to the yield stakeholders.
*/
transaction protocol_tx;
std::vector<crypto::hash> tx_hashes;
// hash cash
@@ -498,6 +619,7 @@ namespace cryptonote
FIELDS(*static_cast<block_header *>(this))
FIELD(miner_tx)
FIELD(protocol_tx)
FIELD(tx_hashes)
if (tx_hashes.size() > CRYPTONOTE_MAX_TX_PER_BLOCK)
return false;
@@ -549,6 +671,23 @@ namespace cryptonote
};
//---------------------------------------------------------------
struct origin_data
{
uint8_t tx_type;
crypto::public_key tx_pub_key;
uint64_t output_index;
//crypto::key_image input_k_image;
//crypto::ec_scalar uniqueness;
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(tx_type)
FIELD(tx_pub_key)
VARINT_FIELD(output_index)
//FIELD(input_k_image)
//FIELD(uniqueness)
END_SERIALIZE()
};
}
namespace std {
@@ -566,7 +705,7 @@ namespace std {
};
}
BLOB_SERIALIZER(cryptonote::txout_to_key);
//BLOB_SERIALIZER(cryptonote::txout_to_key);
BLOB_SERIALIZER(cryptonote::txout_to_scripthash);
VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff);
@@ -94,6 +94,12 @@ namespace cryptonote {
uint64_t full_reward_zone = get_min_block_weight(version);
// Check for height == 0
if (already_generated_coins == 0) {
reward = PREMINE_AMOUNT;
return true;
}
//make it soft
if (median_weight < full_reward_zone) {
median_weight = full_reward_zone;
@@ -104,12 +104,16 @@ namespace boost
inline void serialize(Archive &a, cryptonote::txout_to_key &x, const boost::serialization::version_type ver)
{
a & x.key;
a & x.asset_type;
a & x.unlock_time;
}
template <class Archive>
inline void serialize(Archive &a, cryptonote::txout_to_tagged_key &x, const boost::serialization::version_type ver)
{
a & x.key;
a & x.asset_type;
a & x.unlock_time;
a & x.view_tag;
}
@@ -162,20 +166,38 @@ namespace boost
inline void serialize(Archive &a, cryptonote::transaction_prefix &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.unlock_time;
a & x.vin;
a & x.vout;
a & x.extra;
a & x.type;
if (x.type != cryptonote::transaction_type::MINER && x.type != cryptonote::transaction_type::PROTOCOL) {
a & x.return_address;
a & x.return_pubkey;
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_burnt;
a & x.amount_slippage_limit;
}
}
template <class Archive>
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.unlock_time;
a & x.vin;
a & x.vout;
a & x.extra;
a & x.type;
if (x.type != cryptonote::transaction_type::PROTOCOL) {
a & x.amount_burnt;
if (x.type != cryptonote::transaction_type::MINER) {
a & x.return_address;
a & x.return_pubkey;
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_slippage_limit;
}
}
if (x.version == 1)
{
a & x.signatures;
@@ -188,6 +210,42 @@ namespace boost
}
}
template <class Archive>
inline void serialize(Archive &a, oracle::supply_data &sd, const boost::serialization::version_type ver)
{
a & sd.sal;
a & sd.vsd;
}
template <class Archive>
inline void serialize(Archive &a, oracle::asset_data &ad, const boost::serialization::version_type ver)
{
a & ad.asset_type;
a & ad.spot_price;
a & ad.ma_price;
}
template <class Archive>
inline void serialize(Archive &a, oracle::pricing_record &pr, const boost::serialization::version_type ver)
{
a & pr.pr_version;
a & pr.height;
a & pr.supply;
a & pr.assets;
a & pr.timestamp;
a & pr.signature;
}
template <class Archive>
inline void serialize(Archive &a, cryptonote::yield_block_info &ybi, const boost::serialization::version_type ver)
{
a & ybi.block_height;
a & ybi.slippage_total_this_block;
a & ybi.locked_coins_this_block;
a & ybi.locked_coins_tally;
a & ybi.network_health_percentage;
}
template <class Archive>
inline void serialize(Archive &a, cryptonote::block &b, const boost::serialization::version_type ver)
{
@@ -198,6 +256,7 @@ namespace boost
a & b.nonce;
//------------------
a & b.miner_tx;
a & b.protocol_tx;
a & b.tx_hashes;
}
@@ -339,6 +398,7 @@ namespace boost
a & x.ecdhInfo;
serializeOutPk(a, x.outPk, ver);
a & x.txnFee;
a & x.p_r;
}
template <class Archive>
@@ -373,6 +433,7 @@ namespace boost
a & x.ecdhInfo;
serializeOutPk(a, x.outPk, ver);
a & x.txnFee;
a & x.p_r;
//--------------
a & x.p.rangeSigs;
if (x.p.rangeSigs.empty())
+308 -56
View File
@@ -1,4 +1,5 @@
// Copyright (c) 2014-2022, The Monero Project
// Portions Copyright (c) 2023-2024, Salvium (author: SRCG)
//
// All rights reserved.
//
@@ -29,16 +30,19 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#include <atomic>
#include <csignal>
#include <boost/algorithm/string.hpp>
#include "wipeable_string.h"
#include "string_tools.h"
#include "string_tools_lexical.h"
#include "serialization/string.h"
#include "serialization/pricing_record.h"
#include "cryptonote_format_utils.h"
#include "cryptonote_config.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "ringct/rctSigs.h"
#include "oracle/asset_types.h"
using namespace epee;
@@ -286,7 +290,7 @@ namespace cryptonote
return is_v1_tx(blobdata_ref{tx_blob.data(), tx_blob.size()});
}
//---------------------------------------------------------------
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev)
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od)
{
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
@@ -314,10 +318,10 @@ namespace cryptonote
boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev);
CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address");
return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev);
return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev, use_origin_data, od);
}
//---------------------------------------------------------------
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev)
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od)
{
if (hwdev.compute_key_image(ack, out_key, recv_derivation, real_output_index, received_index, in_ephemeral, ki))
{
@@ -388,6 +392,58 @@ namespace cryptonote
}
}
if (in_ephemeral.pub != out_key) {
if (use_origin_data) {
// 1. Obtain P_change from the output (it is the subaddress public key)
crypto::public_key P_change = crypto::null_pkey;
// SRCG: This is a confusing one - for some reason I was using the line below, and it _seemed_ to work...
// ... but I think it was luck! the "od.output_index" would only work for the TD_ORIGIN data, of course...
//hwdev.derive_subaddress_public_key(out_key, recv_derivation, od.output_index, P_change);
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE) {
hwdev.derive_subaddress_public_key(out_key, recv_derivation, 0, P_change);
} else {
hwdev.derive_subaddress_public_key(out_key, recv_derivation, real_output_index, P_change);
}
// 2. Obtain a separate key_derivation for the _original_ P_change output
// (using the TX public key from the CONVERT TX and the sender's private view key)
crypto::key_derivation derivation_P_change_tx = AUTO_VAL_INIT(derivation_P_change_tx);
CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(od.tx_pub_key, ack.m_view_secret_key, derivation_P_change_tx), false, "Failed to generate key_derivation for P_change");
// 3. Calculate the secret spend key "x_change" for the change output of the CONVERT TX
crypto::secret_key sk_spend = crypto::null_skey;
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation_P_change_tx, od.output_index, spend_skey, sk_spend), false, "Failed to derive secret key for P_change");
// 4. Derive the public key from the secret key for verification purposes
crypto::public_key change_pk;
CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(sk_spend, change_pk), false, "Failed to derive public key for P_change");
CHECK_AND_ASSERT_MES(P_change == change_pk, false, "derived P_change public key does not match P_change");
// 5. Calculate the secret spend key "x_return"
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE) {
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, 0, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'");
} else {
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(recv_derivation, real_output_index, sk_spend, scalar_step1), false, "Failed to derive one-time output secret key 'x_return'");
}
in_ephemeral.sec = scalar_step1;
CHECK_AND_ASSERT_MES(hwdev.secret_key_to_public_key(in_ephemeral.sec, in_ephemeral.pub), false, "Failed to derive one-time output public key 'P_return'");
CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_key,
false, "key image helper precomp: given output pubkey doesn't match the derived one");
// 6. Create the key_image needed to be able to spend the output
hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
return true;
} else {
// Not really anything to do here except throw an exception
CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_key,
false, "key image helper precomp: given output pubkey doesn't match the derived one");
}
}
CHECK_AND_ASSERT_MES(in_ephemeral.pub == out_key,
false, "key image helper precomp: given output pubkey doesn't match the derived one");
}
@@ -906,6 +962,183 @@ namespace cryptonote
return outputs_amount;
}
//---------------------------------------------------------------
std::string asset_type_from_id(const uint32_t asset_type_id)
{
switch (asset_type_id) {
case 0x53414C00:
return "SAL";
case 0x56534400:
return "VSD";
case 0x4255524E:
return "BURN";
case 0x00000000:
return "";
default:
break;
}
// Should probably throw() here
return "";
}
//---------------------------------------------------------------
uint32_t asset_id_from_type(const std::string asset_type)
{
if (asset_type == "SAL") {
return 0x53414C00;
} else if (asset_type == "VSD") {
return 0x56534400;
} else if (asset_type == "BURN") {
return 0x4255524E;
} else if (asset_type == "") {
return 0x00000000;
} else {
// Should probably throw() here
return static_cast<uint32_t>(-1);
}
}
//---------------------------------------------------------------
/**
* The various scenarios that are permitted for Salvium are more extensive than
* they are for Zepyhr / Havan. Specifically, we permit:
*
* MINER_TX: (SRCG => all fees are to be paid in SAL?)
* - input txin_gen (SAL)
* - outputs txout_to_key (SAL) / txout_to_tagged_key (SAL)
*
* PROTOCOL_TX:
* - input txin_gen (SAL) --- ONLY if there are outputs
* - input void ("") --- ONLY if there are NO outputs
* - outputs txout_to_key (SAL, VSD) / txout_to_tagged_key (SAL, VSD)
*
* BURN:
*
* CONVERT:
*
* TRANSFER:
*
* LOCK_FOR_YIELD:
*
*/
bool get_tx_asset_types(const transaction& tx, const crypto::hash &txid, std::string& source, std::string& destination, const bool is_miner_tx) {
// Clear the source
std::set<std::string> source_asset_types;
source = "";
for (size_t i = 0; i < tx.vin.size(); i++) {
if (tx.vin[i].type() == typeid(txin_gen)) {
if (!is_miner_tx) {
LOG_ERROR("txin_gen detected in non-miner TX. Rejecting..");
return false;
}
source_asset_types.insert("SAL");
} else if (tx.vin[i].type() == typeid(txin_to_key)) {
source_asset_types.insert(boost::get<txin_to_key>(tx.vin[i]).asset_type);
} else {
LOG_ERROR("Unexpected input type found: " << tx.vin[i].type().name());
return false;
}
}
std::vector<std::string> sat;
sat.reserve(source_asset_types.size());
std::copy(source_asset_types.begin(), source_asset_types.end(), std::back_inserter(sat));
// Check for empty TX
if (sat.size() == 0) {
CHECK_AND_ASSERT_MES(tx.type == cryptonote::transaction_type::PROTOCOL, false, "Only protocol_tx type can have no vin entry");
CHECK_AND_ASSERT_MES(tx.vin.empty(), false, "Only protocol_tx type can have no vin entry");
CHECK_AND_ASSERT_MES(tx.vout.empty(), false, "Protocol TX with no inputs cannot have outputs");
destination = "";
return true;
}
// Sanity check that we only have 1 source asset type
if (sat.size() != 1) {
LOG_ERROR("Multiple Source Asset types detected. Rejecting..");
return false;
}
source = sat[0];
// Check for empty TX (no outputs)
if (tx.vout.empty()) {
LOG_PRINT_L1("No TX outputs found - returning empty destination");
destination = "";
return true;
}
// Clear the destination
std::set<std::string> destination_asset_types;
destination = "";
for (const auto &out: tx.vout) {
std::string output_asset_type;
bool ok = cryptonote::get_output_asset_type(out, output_asset_type);
if (!ok) {
LOG_ERROR("Unexpected output asset type found: " << out.target.type().name());
return false;
}
destination_asset_types.insert(output_asset_type);
}
std::vector<std::string> dat;
dat.reserve(destination_asset_types.size());
std::copy(destination_asset_types.begin(), destination_asset_types.end(), std::back_inserter(dat));
// Check that we have at least 1 destination_asset_type
if (!dat.size()) {
LOG_ERROR("No supported destinations asset types detected. Rejecting..");
return false;
}
// Handle miner_txs differently - full validation is performed in validate_miner_transaction()
if (is_miner_tx) {
destination = "SAL";
} else {
// Sanity check that we only have 1 or 2 destination asset types
if (dat.size() > 2) {
LOG_ERROR("Too many (" << dat.size() << ") destination asset types detected in non-miner TX. Rejecting..");
return false;
} else if (dat.size() == 1) {
if (sat.size() != 1) {
LOG_ERROR("Impossible input asset types. Rejecting..");
return false;
}
if (dat[0] != source) {
LOG_ERROR("Conversion without change detected ([" << source << "] -> [" << dat[0] << "]). Rejecting..");
return false;
}
destination = dat[0];
} else {
if (sat.size() == 2) {
if (!((dat[0] == "SAL" && dat[1] == "VSD") || (dat[0] == "VSD" && dat[1] == "SAL"))) {
LOG_ERROR("Impossible input asset types. Rejecting..");
return false;
}
}
if (dat[0] == source) {
destination = dat[1];
} else if (dat[1] == source) {
destination = dat[0];
} else {
LOG_ERROR("Conversion outputs are incorrect asset types (source asset type not found - [" << source << "] -> [" << dat[0] << "," << dat[1] << "]). Rejecting..");
return false;
}
}
}
// check both strSource and strDest are supported.
if (std::find(oracle::ASSET_TYPES.begin(), oracle::ASSET_TYPES.end(), source) == oracle::ASSET_TYPES.end()) {
LOG_ERROR("Source Asset type " << source << " is not supported! Rejecting..");
return false;
}
if (destination != "BURN") {
if (std::find(oracle::ASSET_TYPES.begin(), oracle::ASSET_TYPES.end(), destination) == oracle::ASSET_TYPES.end()) {
LOG_ERROR("Destination Asset type " << destination << " is not supported! Rejecting..");
return false;
}
}
return true;
}
//---------------------------------------------------------------
bool get_output_public_key(const cryptonote::tx_out& out, crypto::public_key& output_public_key)
{
// before HF_VERSION_VIEW_TAGS, outputs with public keys are of type txout_to_key
@@ -930,6 +1163,40 @@ namespace cryptonote
: boost::optional<crypto::view_tag>();
}
//---------------------------------------------------------------
bool get_output_asset_type(const cryptonote::tx_out& out, std::string& output_asset_type)
{
// before HF_VERSION_VIEW_TAGS, outputs with public keys are of type txout_to_key
// after HF_VERSION_VIEW_TAGS, outputs with public keys are of type txout_to_tagged_key
if (out.target.type() == typeid(txout_to_key))
output_asset_type = boost::get< txout_to_key>(out.target).asset_type;
else if (out.target.type() == typeid(txout_to_tagged_key))
output_asset_type = boost::get< txout_to_tagged_key >(out.target).asset_type;
else
{
LOG_ERROR("Unexpected output target type found: " << out.target.type().name() << " - cannot retrieve output_asset_type");
return false;
}
return true;
}
//---------------------------------------------------------------
bool get_output_unlock_time(const cryptonote::tx_out& out, uint64_t& output_unlock_time)
{
// before HF_VERSION_VIEW_TAGS, outputs with public keys are of type txout_to_key
// after HF_VERSION_VIEW_TAGS, outputs with public keys are of type txout_to_tagged_key
if (out.target.type() == typeid(txout_to_key))
output_unlock_time = boost::get< txout_to_key>(out.target).unlock_time;
else if (out.target.type() == typeid(txout_to_tagged_key))
output_unlock_time = boost::get< txout_to_tagged_key >(out.target).unlock_time;
else
{
LOG_ERROR("Unexpected output target type found: " << out.target.type().name() << " - cannot retrieve output_unlock_time");
return false;
}
return true;
}
//---------------------------------------------------------------
std::string short_hash_str(const crypto::hash& h)
{
std::string res = string_tools::pod_to_hex(h);
@@ -939,7 +1206,7 @@ namespace cryptonote
return res;
}
//---------------------------------------------------------------
void set_tx_out(const uint64_t amount, const crypto::public_key& output_public_key, const bool use_view_tags, const crypto::view_tag& view_tag, tx_out& out)
void set_tx_out(const uint64_t amount, const std::string& asset_type, const uint64_t unlock_time, const crypto::public_key& output_public_key, const bool use_view_tags, const crypto::view_tag& view_tag, tx_out& out)
{
out.amount = amount;
if (use_view_tags)
@@ -947,12 +1214,16 @@ namespace cryptonote
txout_to_tagged_key ttk;
ttk.key = output_public_key;
ttk.view_tag = view_tag;
ttk.asset_type = asset_type;
ttk.unlock_time = unlock_time;
out.target = ttk;
}
else
{
txout_to_key tk;
tk.key = output_public_key;
tk.asset_type = asset_type;
tk.unlock_time = unlock_time;
out.target = tk;
}
}
@@ -1062,10 +1333,22 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(output_index < additional_derivations.size(), boost::none, "wrong number of additional derivations");
if (out_can_be_to_acc(view_tag_opt, additional_derivations[output_index], output_index, &hwdev))
{
// HERE BE DRAGONS!!!
// SRCG: This is NOT going to work for PROTOCOL_TX except where there is only a single output
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], output_index, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
// LAND AHOY!!!
auto found = subaddresses.find(subaddress_spendkey);
if (found != subaddresses.end())
return subaddress_receive_info{ found->second, additional_derivations[output_index] };
// If we get here, odds are that it is a PROTOCOL_TX (rare for other TX types to have additional derivations!)
if (output_index != 0) {
// Try the derivation with a 0 index as an override - CONVERT / YIELD TXs cannot know their index in the PROTOCOL_TX, so they use 0 in all cases
CHECK_AND_ASSERT_MES(hwdev.derive_subaddress_public_key(out_key, additional_derivations[output_index], 0, subaddress_spendkey), boost::none, "Failed to derive subaddress public key");
auto found_protocol = subaddresses.find(subaddress_spendkey);
if (found_protocol != subaddresses.end())
return subaddress_receive_info{ found_protocol->second, additional_derivations[output_index] };
}
}
}
return boost::none;
@@ -1113,11 +1396,9 @@ namespace cryptonote
{
switch (decimal_point)
{
case 12:
case 9:
case 6:
case 3:
case 0:
case 8:
case 5:
case 2:
default_decimal_point = decimal_point;
break;
default:
@@ -1136,18 +1417,14 @@ namespace cryptonote
decimal_point = default_decimal_point;
switch (decimal_point)
{
case 12:
return "monero";
case 9:
return "millinero";
case 6:
return "micronero";
case 3:
return "nanonero";
case 0:
return "piconero";
default:
ASSERT_MES_AND_THROW("Invalid decimal point specification: " << decimal_point);
case 8:
return "sal";
case 5:
return "millisal";
case 2:
return "microsal";
default:
ASSERT_MES_AND_THROW("Invalid decimal point specification: " << decimal_point);
}
}
//---------------------------------------------------------------
@@ -1229,7 +1506,7 @@ namespace cryptonote
char *end = NULL;
errno = 0;
const unsigned long long ull = strtoull(buf, &end, 10);
CHECK_AND_ASSERT_THROW_MES(ull != ULONG_MAX || errno == 0, "Failed to parse rounded amount: " << buf);
CHECK_AND_ASSERT_THROW_MES(ull != ULLONG_MAX || errno == 0, "Failed to parse rounded amount: " << buf);
CHECK_AND_ASSERT_THROW_MES(ull != 0 || amount == 0, "Overflow in rounding");
return ull;
}
@@ -1457,38 +1734,7 @@ namespace cryptonote
blob = &bdref;
}
bool hash_result = get_object_hash(get_block_hashing_blob(b), res);
if (!hash_result)
return false;
if (b.miner_tx.vin.size() == 1 && b.miner_tx.vin[0].type() == typeid(cryptonote::txin_gen))
{
const cryptonote::txin_gen &txin_gen = boost::get<cryptonote::txin_gen>(b.miner_tx.vin[0]);
if (txin_gen.height != 202612)
return true;
}
// EXCEPTION FOR BLOCK 202612
const std::string correct_blob_hash_202612 = "3a8a2b3a29b50fc86ff73dd087ea43c6f0d6b8f936c849194d5c84c737903966";
const std::string existing_block_id_202612 = "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698";
crypto::hash block_blob_hash = get_blob_hash(*blob);
if (string_tools::pod_to_hex(block_blob_hash) == correct_blob_hash_202612)
{
string_tools::hex_to_pod(existing_block_id_202612, res);
return true;
}
{
// make sure that we aren't looking at a block with the 202612 block id but not the correct blobdata
if (string_tools::pod_to_hex(res) == existing_block_id_202612)
{
LOG_ERROR("Block with block id for 202612 but incorrect block blob hash found!");
res = null_hash;
return false;
}
}
return hash_result;
return get_object_hash(get_block_hashing_blob(b), res);
}
//---------------------------------------------------------------
bool get_block_hash(const block& b, crypto::hash& res)
@@ -1598,10 +1844,16 @@ namespace cryptonote
crypto::hash get_tx_tree_hash(const block& b)
{
std::vector<crypto::hash> txs_ids;
txs_ids.reserve(1 + b.tx_hashes.size());
txs_ids.reserve(2 + b.tx_hashes.size());
// Miner TX
crypto::hash h = null_hash;
size_t bl_sz = 0;
CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(b.miner_tx, h, bl_sz), "Failed to calculate transaction hash");
CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(b.miner_tx, h, bl_sz), "Failed to calculate transaction hash (miner_tx)");
txs_ids.push_back(h);
// Protocol TX
h = null_hash;
bl_sz = 0;
CHECK_AND_ASSERT_THROW_MES(get_transaction_hash(b.protocol_tx, h, bl_sz), "Failed to calculate transaction hash (protocol_tx)");
txs_ids.push_back(h);
for(auto& th: b.tx_hashes)
txs_ids.push_back(th);
@@ -1,4 +1,5 @@
// Copyright (c) 2014-2022, The Monero Project
// Portions Copyright (c) 2023-2024, Salvium (author: SRCG)
//
// All rights reserved.
//
@@ -89,7 +90,7 @@ namespace cryptonote
void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id);
bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id);
bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id);
void set_tx_out(const uint64_t amount, const crypto::public_key& output_public_key, const bool use_view_tags, const crypto::view_tag& view_tag, tx_out& out);
void set_tx_out(const uint64_t amount, const std::string& asset_type, const uint64_t unlock_time, const crypto::public_key& output_public_key, const bool use_view_tags, const crypto::view_tag& view_tag, tx_out& out);
bool check_output_types(const transaction& tx, const uint8_t hf_version);
bool out_can_be_to_acc(const boost::optional<crypto::view_tag>& view_tag_opt, const crypto::key_derivation& derivation, const size_t output_index, hw::device *hwdev = nullptr);
bool is_out_to_acc(const account_keys& acc, const crypto::public_key& output_public_key, const crypto::public_key& tx_pub_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t output_index, const boost::optional<crypto::view_tag>& view_tag_opt = boost::optional<crypto::view_tag>());
@@ -103,8 +104,8 @@ namespace cryptonote
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
bool get_tx_fee(const transaction& tx, uint64_t & fee);
uint64_t get_tx_fee(const transaction& tx);
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev);
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev);
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od);
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev, const bool use_origin_data, const origin_data& od);
void get_blob_hash(const blobdata& blob, crypto::hash& res);
void get_blob_hash(const blobdata_ref& blob, crypto::hash& res);
crypto::hash get_blob_hash(const blobdata& blob);
@@ -129,8 +130,13 @@ namespace cryptonote
bool parse_and_validate_block_from_blob(const blobdata_ref& b_blob, block& b, crypto::hash &block_hash);
bool get_inputs_money_amount(const transaction& tx, uint64_t& money);
uint64_t get_outs_money_amount(const transaction& tx);
std::string asset_type_from_id(const uint32_t asset_type_id);
uint32_t asset_id_from_type(const std::string asset_type);
bool get_tx_asset_types(const transaction& tx, const crypto::hash &txid, std::string& source, std::string& destination, const bool is_miner_tx);
bool get_output_public_key(const cryptonote::tx_out& out, crypto::public_key& output_public_key);
boost::optional<crypto::view_tag> get_output_view_tag(const cryptonote::tx_out& out);
bool get_output_asset_type(const cryptonote::tx_out& out, std::string& output_asset_type);
bool get_output_unlock_time(const cryptonote::tx_out& out, uint64_t& output_unlock_time);
bool check_inputs_types_supported(const transaction& tx);
bool check_outs_valid(const transaction& tx);
bool parse_amount(uint64_t& amount, const std::string& str_amount);
+8 -1
View File
@@ -523,7 +523,7 @@ namespace cryptonote
bool miner::worker_thread()
{
const uint32_t th_local_index = m_thread_index++; // atomically increment, getting value before increment
crypto::rx_set_miner_thread(th_local_index, tools::get_max_concurrency());
bool rx_set = false;
MLOG_SET_THREAD_NAME(std::string("[miner ") + std::to_string(th_local_index) + "]");
MGINFO("Miner thread was started ["<< th_local_index << "]");
@@ -575,6 +575,13 @@ namespace cryptonote
b.nonce = nonce;
crypto::hash h;
if ((b.major_version >= RX_BLOCK_VERSION) && !rx_set)
{
crypto::rx_set_miner_thread(th_local_index, tools::get_max_concurrency());
rx_set = true;
}
m_gbh(b, height, NULL, tools::get_max_concurrency(), h);
if(check_hash(h, local_diff))
+4 -4
View File
@@ -52,7 +52,7 @@ namespace cryptonote
// load
template <template <bool> class Archive>
bool do_serialize(Archive<false>& ar)
bool member_do_serialize(Archive<false>& ar)
{
// size - 1 - because of variant tag
for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size)
@@ -73,7 +73,7 @@ namespace cryptonote
// store
template <template <bool> class Archive>
bool do_serialize(Archive<true>& ar)
bool member_do_serialize(Archive<true>& ar)
{
if(TX_EXTRA_PADDING_MAX_COUNT < size)
return false;
@@ -129,7 +129,7 @@ namespace cryptonote
// load
template <template <bool> class Archive>
bool do_serialize(Archive<false>& ar)
bool member_do_serialize(Archive<false>& ar)
{
std::string field;
if(!::do_serialize(ar, field))
@@ -142,7 +142,7 @@ namespace cryptonote
// store
template <template <bool> class Archive>
bool do_serialize(Archive<true>& ar)
bool member_do_serialize(Archive<true>& ar)
{
std::ostringstream oss;
binary_archive<true> oar(oss);
+6 -1
View File
@@ -42,7 +42,12 @@ namespace cryptonote
static_assert(unsigned(relay_method::none) == 0, "default m_relay initialization is not to relay_method::none");
relay_method m_relay; // gives indication on how tx should be relayed (if at all)
bool m_verifivation_failed; //bad tx, should drop connection
bool m_verifivation_failed; //bad tx, tx should not enter mempool and connection should be dropped unless m_no_drop_offense
// Do not add to mempool, do not relay, but also do not punish the peer for sending or drop
// connections to them. Used for low fees, tx_extra too big, "relay-only rules". Not to be
// confused with breaking soft fork rules, because tx could be later added to the chain if mined
// because it does not violate consensus rules.
bool m_no_drop_offense;
bool m_verifivation_impossible; //the transaction is related with an alternative blockchain
bool m_added_to_pool;
bool m_low_mixin;
+147 -41
View File
@@ -30,6 +30,7 @@
#pragma once
#include <array>
#include <stdexcept>
#include <string>
#include <boost/uuid/uuid.hpp>
@@ -43,16 +44,19 @@
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
#define CURRENT_TRANSACTION_VERSION 2
#define CURRENT_BLOCK_MAJOR_VERSION 1
#define CURRENT_BLOCK_MINOR_VERSION 0
#define CURRENT_BLOCK_MINOR_VERSION 1
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE 10
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW 60
// MONEY_SUPPLY - total number coins to be generated
#define MONEY_SUPPLY ((uint64_t)(-1))
#define MONEY_SUPPLY ((uint64_t)(18440000000000000ull)) // 184.4M coins * pow(10, 8)
#define EMISSION_SPEED_FACTOR_PER_MINUTE (20)
#define FINAL_SUBSIDY_PER_MINUTE ((uint64_t)300000000000) // 3 * pow(10, 11)
#define FINAL_SUBSIDY_PER_MINUTE ((uint64_t)30000000) // 3 * pow(10, 7)
#define BURN_LOCK_PERIOD 0
#define CONVERT_LOCK_PERIOD 0
#define CRYPTONOTE_REWARD_BLOCKS_WINDOW 100
#define CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 60000 //size of block (bytes) after which reward for block calculated using block size
@@ -61,20 +65,23 @@
#define CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE 100000 // size in blocks of the long term block weight median window
#define CRYPTONOTE_SHORT_TERM_BLOCK_WEIGHT_SURGE_FACTOR 50
#define CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE 600
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT 12
#define CRYPTONOTE_DISPLAY_DECIMAL_POINT 8
// COIN - number of smallest units in one coin
#define COIN ((uint64_t)1000000000000) // pow(10, 12)
#define COIN ((uint64_t)100000000) // pow(10, 8)
#define FEE_PER_KB_OLD ((uint64_t)10000000000) // pow(10, 10)
#define FEE_PER_KB ((uint64_t)2000000000) // 2 * pow(10, 9)
#define FEE_PER_BYTE ((uint64_t)300000)
#define DYNAMIC_FEE_PER_KB_BASE_FEE ((uint64_t)2000000000) // 2 * pow(10,9)
#define DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD ((uint64_t)10000000000000) // 10 * pow(10,12)
#define DYNAMIC_FEE_PER_KB_BASE_FEE_V5 ((uint64_t)2000000000 * (uint64_t)CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5)
//#define FEE_PER_KB_OLD ((uint64_t)1000000) // pow(10, 6)
#define FEE_PER_KB ((uint64_t)200000) // 2 * pow(10, 5)
#define FEE_PER_BYTE ((uint64_t)30)
#define DYNAMIC_FEE_PER_KB_BASE_FEE ((uint64_t)200000) // 2 * pow(10,5)
#define DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD ((uint64_t)1000000000) // 10 * pow(10,8)
#define DYNAMIC_FEE_PER_KB_BASE_FEE_V5 ((uint64_t)200000 * (uint64_t)CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5)
#define DYNAMIC_FEE_REFERENCE_TRANSACTION_WEIGHT ((uint64_t)3000)
#define ORPHANED_BLOCKS_MAX_COUNT 100
#define PREMINE_AMOUNT ((uint64_t)2210000000000000ull) // 12% of MONEY_SUPPLY
#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 DIFFICULTY_TARGET_V2 120 // seconds
#define DIFFICULTY_TARGET_V1 60 // seconds - before first fork
@@ -157,7 +164,7 @@
#define RPC_IP_FAILS_BEFORE_BLOCK 3
#define CRYPTONOTE_NAME "bitmonero"
#define CRYPTONOTE_NAME "salvium"
#define CRYPTONOTE_BLOCKCHAINDATA_FILENAME "data.mdb"
#define CRYPTONOTE_BLOCKCHAINDATA_LOCK_FILENAME "lock.mdb"
#define P2P_NET_DATA_FILENAME "p2pstate.bin"
@@ -166,6 +173,7 @@
#define THREAD_STACK_SIZE 5 * 1024 * 1024
/*
#define HF_VERSION_DYNAMIC_FEE 4
#define HF_VERSION_MIN_MIXIN_4 6
#define HF_VERSION_MIN_MIXIN_6 7
@@ -187,6 +195,29 @@
#define HF_VERSION_BULLETPROOF_PLUS 15
#define HF_VERSION_VIEW_TAGS 15
#define HF_VERSION_2021_SCALING 15
*/
#define HF_VERSION_DYNAMIC_FEE 1
#define HF_VERSION_PER_BYTE_FEE 1
#define HF_VERSION_ENFORCE_MIN_AGE 1
#define HF_VERSION_EXACT_COINBASE 1
#define HF_VERSION_CLSAG 1
#define HF_VERSION_DETERMINISTIC_UNLOCK_TIME 1
#define HF_VERSION_SMALLER_BP 1
#define HF_VERSION_MIN_V2_COINBASE_TX 1
#define HF_VERSION_REJECT_SIGS_IN_COINBASE 1
#define HF_VERSION_BULLETPROOF_PLUS 1
#define HF_VERSION_ENABLE_RETURN 1
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT 2
#define HF_VERSION_VIEW_TAGS 2
#define HF_VERSION_2021_SCALING 2
#define HF_VERSION_ENABLE_CONVERT 2
#define HF_VERSION_ENABLE_ORACLE 2
#define HF_VERSION_SLIPPAGE_YIELD 2
#define TESTNET_VERSION 5
#define STAGENET_VERSION 1
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
#define CRYPTONOTE_SCALING_2021_FEE_ROUNDING_PLACES 2
@@ -206,6 +237,9 @@
#define DNS_BLOCKLIST_LIFETIME (86400 * 8)
#define PRICING_RECORD_VALID_BLOCKS 10
#define PRICING_RECORD_VALID_TIME_DIFF_FROM_BLOCK 120 // seconds
//The limit is enough for the mandatory transaction content with 16 outputs (547 bytes),
//a custom tag (1 byte) and up to 32 bytes of custom data for each recipient.
// (1+32) + (1+1+16*32) + (1+16*32) = 1060
@@ -219,18 +253,24 @@ namespace config
uint64_t const DEFAULT_DUST_THRESHOLD = ((uint64_t)2000000000); // 2 * pow(10, 9)
uint64_t const BASE_REWARD_CLAMP_THRESHOLD = ((uint64_t)100000000); // pow(10, 8)
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 18;
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 19;
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 42;
uint16_t const P2P_DEFAULT_PORT = 18080;
uint16_t const RPC_DEFAULT_PORT = 18081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 18082;
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 0x3ef318; // SaLv
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0x55ef318; // SaLvi
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0xf5ef318; // SaLvs
uint16_t const P2P_DEFAULT_PORT = 19080;
uint16_t const RPC_DEFAULT_PORT = 19081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 19082;
boost::uuids::uuid const NETWORK_ID = { {
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x10
} }; // Bender's nightmare
std::string const GENESIS_TX = "013c01ff0001ffffffffffff03029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121017767aafcde9be00dcfd098715ebcf7f410daebc582fda69d24a28e9d0bc890d1";
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x82, 0x53, 0x41, 0x4C, 0xFF, 0x10
} };
std::string const GENESIS_TX = "0201ff000180c0d0c7bbbff60302c33815291bac1b6d5c685129c1de6383e550688d005a3ce2b66a96b7050579060353414c3c00000000000000210149117096744b390170a118fc14d8f13edb40a7d2764fde3043d9fbae7d2efdef010000";
uint32_t const GENESIS_NONCE = 10000;
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
std::string const TREASURY_ADDRESS = "SaLvdVTaMJp5hrGv2rDWzaCrM6Wrq2T4tNBPX8kvuAJv7iUiYNy4vceFskGRAawnBDiqZ9jWYXZmWemRnEKtWmNMeuSXZg6jwtx";
// Hash domain separators
const char HASH_KEY_BULLETPROOF_EXPONENT[] = "bulletproof";
const char HASH_KEY_BULLETPROOF_PLUS_EXPONENT[] = "bulletproof_plus";
@@ -258,34 +298,84 @@ namespace config
// Multisig
const uint32_t MULTISIG_MAX_SIGNERS{16};
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.network:8443", "oracle.salvium.network:8443", "oracle.salvium.network:8443"}};
std::string const ORACLE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n"
"MIIDRDCCAjYGByqGSM44BAEwggIpAoIBAQCZP7IJ5PcNvGbWiEqAioKF9wViVxEN\n"
"ZBDHvhr8IR6KoSYUXMU154DC6NDiSr6FtPBWuw9LcXlfWdG0l3hd6zObg0GpEQig\n"
"jEeOEeBm45ug9lMBSZiaiCHeU8ats1YIQBYDO8m7iAj9Q9/N1nJHDpypsVu5WGLm\n"
"+xSmcNULTbqwJ4Sr49TD++sv2MZEJeYRwmmxlqeFFtZlxguwJ90Y5U7aSi4w4vaU\n"
"pu/Ce6EWi8pVhUlM5xBBk3tc+Z6FMMgKFN/kHyu3SbxFaRQppbsTo0N3yDAr3sN3\n"
"4JmXpRmDidd3czfKlFko11YwK9lohjrgBnStuFRBxDACx4NRfvRfwPqnAh0AhKyn\n"
"pbe2No+7lLGSWuQvIEz+2o6coQ3ZWPbxqQKCAQEAkErfS61wvKxbMwPuuqhCpZG/\n"
"uQ+WYHwRwyxpU7ImKiH6ubqModIvZoHrRD8MIJhbRmBlA58SSnBWrEcAUIaaDM6Z\n"
"xX/VyOFy2mJH3TJJa83oZe275w1JMVrVq1ZybXSYF595zAHNiJcYsskqTbZP8S30\n"
"i3Bq//HMUaRhmB60BLmPpmgF3FVsRkCyEL/yH9cUQWdUcuxIG3C7EzgxGUCaR42J\n"
"cu+NN8z6W/m/joEe6QkFT3tLh1yXIFBK1MamWC0EZ6YCMcozZfGQ15P3rMrGptKN\n"
"+YQRNusTDSqBky+f40dLiYcT28ePQWNPLdsZTqoGWGawqCyWWCh5eWJZSqJPfQOC\n"
"AQYAAoIBAQCE+8kHJmagnDPQWiuHziNha5yia7viwasxcsKhYGx+Z3wVbMrDPwLo\n"
"CUgljEEsOKXLZsg/EmfVQu9nYoTcMa0hNq0/0bEV9oZ0t4O8gLp2Y4URLngR9zxE\n"
"WaVgFLlNtndHUQA2kquP3XLkv/TZVQaqne6tO6p4gLC4ky0YH0vZhWXMOH/4Xfgf\n"
"FZHC7SBC3oYsK9UKX3tJoibcL9L18GOe27pIw70x0280IB/C+TBnAXjslNgJe5ZU\n"
"rSdr1h2nXji0rXL9DoypVC40QGIzzjCGMsSBnSYgVuITeqX8/o/w5LBK8Dl5wXFt\n"
"F9dg9A0deyw/3CA3gwB32zkfi4MEH+il\n"
"-----END PUBLIC KEY-----\n";
/*
std::string const ORACLE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n"
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5YBxWx1AZCA9jTUk8Pr2uZ9jpfRt\n"
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
"-----END PUBLIC KEY-----\n";
*/
namespace testnet
{
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 53;
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 54;
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 63;
uint16_t const P2P_DEFAULT_PORT = 28080;
uint16_t const RPC_DEFAULT_PORT = 28081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 28082;
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 0x15beb318; // SaLvT
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0xd055eb318; // SaLvTi
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0xa59eb318; // SaLvTs
uint16_t const P2P_DEFAULT_PORT = 29080;
uint16_t const RPC_DEFAULT_PORT = 29081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 29082;
boost::uuids::uuid const NETWORK_ID = { {
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x11
} }; // Bender's daydream
std::string const GENESIS_TX = "013c01ff0001ffffffffffff03029b2e4c0281c0b02e7c53291a94d1d0cbff8883f8024f5142ee494ffbbd08807121017767aafcde9be00dcfd098715ebcf7f410daebc582fda69d24a28e9d0bc890d1";
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x82, 0x53, 0x41, 0x4C, 0x00, TESTNET_VERSION
} };
std::string const GENESIS_TX = "020001ff000180c0d0c7bbbff6030279e90d3da9f9568396c5795833e6aed334d10b6bc08219de189e3ac6fade73c50353414c3c00000000000000210118c0fd33040975cb28c52cca0005a909661afeec61944e42b8646e069fd04209010000";
uint32_t const GENESIS_NONCE = 10001;
const uint64_t STAKE_LOCK_PERIOD = 20;
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.network:8443", "oracle.salvium.network:8443", "oracle.salvium.network:8443"}};
std::string const ORACLE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n"
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5YBxWx1AZCA9jTUk8Pr2uZ9jpfRt\n"
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
"-----END PUBLIC KEY-----\n";
std::string const TREASURY_ADDRESS = "SaLvTyLFta9BiAXeUfFkKvViBkFt4ay5nEUBpWyDKewYggtsoxBbtCUVqaBjtcCDyY1euun8Giv7LLEgvztuurLo5a6Km1zskZn36";
}
namespace stagenet
{
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 24;
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 25;
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 36;
uint16_t const P2P_DEFAULT_PORT = 38080;
uint16_t const RPC_DEFAULT_PORT = 38081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 38082;
uint64_t const CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX = 0x149eb318; // SaLvS
uint64_t const CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX = 0xf343eb318; // SaLvSi
uint64_t const CRYPTONOTE_PUBLIC_SUBADDRESS_BASE58_PREFIX = 0x2d47eb318; // SaLvSs
uint16_t const P2P_DEFAULT_PORT = 39080;
uint16_t const RPC_DEFAULT_PORT = 39081;
uint16_t const ZMQ_RPC_DEFAULT_PORT = 39082;
boost::uuids::uuid const NETWORK_ID = { {
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x00, 0x82, 0x16, 0xA1, 0xA1, 0x12
} }; // Bender's daydream
0x12 ,0x30, 0xF1, 0x71 , 0x61, 0x04 , 0x41, 0x61, 0x17, 0x31, 0x82, 0x53, 0x41, 0x4C, 0x80, STAGENET_VERSION
} };
std::string const GENESIS_TX = "013c01ff0001ffffffffffff0302df5d56da0c7d643ddd1ce61901c7bdc5fb1738bfe39fbe69c28a3a7032729c0f2101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b";
uint32_t const GENESIS_NONCE = 10002;
const uint64_t STAKE_LOCK_PERIOD = 20;
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.network:8443", "oracle.salvium.network:8443", "oracle.salvium.network:8443"}};
std::string const ORACLE_PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n"
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE5YBxWx1AZCA9jTUk8Pr2uZ9jpfRt\n"
"KWv3Vo1/Gny+1vfaxsXhBQiG1KlHkafNGarzoL0WHW4ocqaaqF5iv8i35A==\n"
"-----END PUBLIC KEY-----\n";
std::string const TREASURY_ADDRESS = "fuLMowH85abK8nz9BBMEem7MAfUbQu4aSHHUV9j5Z86o6Go9Lv2U5ZQiJCWPY9R9HA8p5idburazjAhCqDngLo7fYPCD9ciM9ee1A";
}
}
@@ -310,6 +400,10 @@ namespace cryptonote
boost::uuids::uuid const NETWORK_ID;
std::string const GENESIS_TX;
uint32_t const GENESIS_NONCE;
std::array<std::string, 3> const ORACLE_URLS;
std::string const ORACLE_PUBLIC_KEY;
uint64_t STAKE_LOCK_PERIOD;
std::string TREASURY_ADDRESS;
};
inline const config_t& get_config(network_type nettype)
{
@@ -322,7 +416,11 @@ namespace cryptonote
::config::ZMQ_RPC_DEFAULT_PORT,
::config::NETWORK_ID,
::config::GENESIS_TX,
::config::GENESIS_NONCE
::config::GENESIS_NONCE,
::config::ORACLE_URLS,
::config::ORACLE_PUBLIC_KEY,
::config::STAKE_LOCK_PERIOD,
::config::TREASURY_ADDRESS
};
static const config_t testnet = {
::config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX,
@@ -333,7 +431,11 @@ namespace cryptonote
::config::testnet::ZMQ_RPC_DEFAULT_PORT,
::config::testnet::NETWORK_ID,
::config::testnet::GENESIS_TX,
::config::testnet::GENESIS_NONCE
::config::testnet::GENESIS_NONCE,
::config::testnet::ORACLE_URLS,
::config::testnet::ORACLE_PUBLIC_KEY,
::config::testnet::STAKE_LOCK_PERIOD,
::config::testnet::TREASURY_ADDRESS
};
static const config_t stagenet = {
::config::stagenet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX,
@@ -344,7 +446,11 @@ namespace cryptonote
::config::stagenet::ZMQ_RPC_DEFAULT_PORT,
::config::stagenet::NETWORK_ID,
::config::stagenet::GENESIS_TX,
::config::stagenet::GENESIS_NONCE
::config::stagenet::GENESIS_NONCE,
::config::stagenet::ORACLE_URLS,
::config::stagenet::ORACLE_PUBLIC_KEY,
::config::stagenet::STAKE_LOCK_PERIOD,
::config::stagenet::TREASURY_ADDRESS
};
switch (nettype)
{
File diff suppressed because it is too large Load Diff
+108 -8
View File
@@ -263,6 +263,21 @@ namespace cryptonote
*/
bool cleanup_handle_incoming_blocks(bool force_sync = false);
/**
* @brief gets the pricing record for the specified timestamp
*
* @return false if method failed to obtain pricing record from oracle, otherwise true
*/
bool get_pricing_record(oracle::pricing_record &pr, std::map<std::string, uint64_t> &circ_supply, uint64_t timestamp);
/**
* @brief gets the latest pricing record that was in the last 10 block.
* If no pricing record found in the past 10 block, fails.
*
* @return false if method failed to obtain pricing, otherwise true
*/
bool get_latest_acceptable_pr(oracle::pricing_record& pr) const;
/**
* @brief search the blockchain for a transaction by hash
*
@@ -516,13 +531,13 @@ namespace cryptonote
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp);
/**
* @brief get number of outputs of an amount past the minimum spendable age
* @brief get number of outputs of an asset type past the minimum spendable age
*
* @param amount the output amount
* @param asset_type the asset type to query
*
* @return the number of mature outputs
* @return the number of mature outputs of the asset type
*/
uint64_t get_num_mature_outputs(uint64_t amount) const;
uint64_t get_num_mature_outputs(const std::string asset_type) const;
/**
* @brief get the public key for an output
@@ -570,7 +585,7 @@ namespace cryptonote
* @param return-by-reference distribution the start offset of the first rct output in this block (same as previous if none)
* @param return-by-reference base how many outputs of that amount are before the stated distribution
*/
bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const;
bool get_output_distribution(uint64_t amount, std::string asset_type, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base, uint64_t &num_spendable_global_outs) const;
/**
* @brief gets the global indices for outputs from a given transaction
@@ -584,8 +599,8 @@ namespace cryptonote
*
* @return false if the transaction does not exist, or if no indices are found, otherwise true
*/
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const;
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const;
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<std::pair<uint64_t, uint64_t>>& indexs) const;
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<std::pair<uint64_t, uint64_t>>>& indexs) const;
/**
* @brief stores the blockchain
@@ -604,7 +619,7 @@ namespace cryptonote
* can be reconstituted by the receiver. This function expands
* that implicit data.
*/
static bool expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys);
static bool expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys, const uint8_t &hf_version);
/**
* @brief validates a transaction's inputs
@@ -731,6 +746,8 @@ namespace cryptonote
*/
uint64_t get_current_cumulative_block_weight_median() const;
int get_yield_info(const uint64_t start_height, const uint64_t end_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_container);
/**
* @brief gets the difficulty of the block with a given height
*
@@ -1130,6 +1147,55 @@ namespace cryptonote
*/
uint64_t get_adjusted_time(uint64_t height) const;
/**
* 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, uint64_t>>& yield_payouts);
/**
* @brief get the complete YBI cache
*
* Retrieve the YBI local cache.
* If the cache is out of date, the cache will (attempt to) be rebuilt
* before being returned.
*
* @return TRUE if the call is successful, FALSE otherwise
*/
bool get_ybi_cache(std::map<uint64_t, yield_block_info>& ybi_cache);
/**
* @brief get the YBI entry for a particular height from the cache
*
* Retrieve the YBI entry for the specified height from the local cache.
* If the cache is out of date, the cache will (attempt to) be rebuilt
* before the entry is obtained.
*
* @return TRUE if the entry was located and returned, FALSE otherwise
*/
bool get_ybi_entry(const uint64_t height, cryptonote::yield_block_info& ybi);
/**
* (re)build the yield_block_info cache from the blockchain
*
* @return TRUE if the cache rebuilt correctly, FALSE otherwise
*/
bool rebuild_ybi_cache();
/**
* @brief validate the yield_block_info cache
*
* Checks that the m_yield_block_info_cache is fully populated by
* checking the size of the map, and making sure it has the most recent entry
* and the oldest expected entry as well
*
* Returns TRUE if the cache is intact, full, and up-to-date, FALSE otherwise
*
* @return TRUE if cache is OK, FALSE otherwise
*/
bool validate_ybi_cache();
#ifndef IN_UNIT_TESTS
private:
#endif
@@ -1235,6 +1301,11 @@ namespace cryptonote
// cache for verifying transaction RCT non semantics
mutable rct_ver_cache_t m_rct_ver_cache;
/**
* @brief hashmap linking blockchain height to YBI struct for that height
*/
std::map<uint64_t, yield_block_info> m_yield_block_info_cache;
/**
* @brief collects the keys for all outputs being "spent" as an input
*
@@ -1405,6 +1476,20 @@ namespace cryptonote
*/
bool prevalidate_miner_transaction(const block& b, uint64_t height, uint8_t hf_version);
/**
* @brief sanity checks a protocol transaction before validating an entire block
*
* This function merely checks basic things like the structure of the protocol
* transaction, the unlock time, and that the amount doesn't overflow.
*
* @param b the block containing the protocol transaction
* @param height the height at which the block will be added
* @param hf_version the consensus rules to apply
*
* @return false if anything is found wrong with the protocol transaction, otherwise true
*/
bool prevalidate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version);
/**
* @brief validates a miner (coinbase) transaction
*
@@ -1423,6 +1508,21 @@ namespace cryptonote
*/
bool validate_miner_transaction(const block& b, size_t cumulative_block_weight, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version);
/**
* @brief validates a protocol (coinbase) transaction
*
* This function makes sure that the protocol rules are being implemented correctly
* and that the conversions and yield payouts match what is expected.
*
* @param b the block containing the miner transaction to be validated
* @param height the blockchain's weight
* @param txs a vector containing all the TXs and their blobs, needed to obtain tx_types, asset_types and burnt amounts
* @param version hard fork version for that transaction
*
* @return false if anything is found wrong with the protocol transaction, otherwise true
*/
bool validate_protocol_transaction(const block& b, uint64_t height, std::vector<std::pair<transaction, blobdata>>& txs, const std::map<std::string, uint64_t>& circ_supply, uint8_t hf_version);
/**
* @brief reverts the blockchain to its previous state following a failed switch
*
+32 -12
View File
@@ -171,7 +171,7 @@ namespace cryptonote
static const command_line::arg_descriptor<std::string> arg_check_updates = {
"check-updates"
, "Check for new versions of monero: [disabled|notify|download|update]"
, "notify"
, "disabled"
};
static const command_line::arg_descriptor<bool> arg_fluffy_blocks = {
"fluffy-blocks"
@@ -504,7 +504,7 @@ namespace cryptonote
{
MWARNING("Found old-style blockchain.bin in " << old_files.string());
MWARNING("Monero now uses a new format. You can either remove blockchain.bin to start syncing");
MWARNING("the blockchain anew, or use monero-blockchain-export and monero-blockchain-import to");
MWARNING("the blockchain anew, or use salvium-blockchain-export and salvium-blockchain-import to");
MWARNING("convert your existing blockchain.bin to the new format. See README.md for instructions.");
return false;
}
@@ -836,7 +836,7 @@ namespace cryptonote
bad_semantics_txes_lock.unlock();
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = version == 1 ? 1 : 2;
const size_t max_tx_version = (version < HF_VERSION_SLIPPAGE_YIELD) ? 2 : CURRENT_TRANSACTION_VERSION;
if (tx.version == 0 || tx.version > max_tx_version)
{
// v2 is the latest one we know
@@ -925,7 +925,12 @@ namespace cryptonote
tx_info[n].result = false;
break;
case rct::RCTTypeSimple:
if (!rct::verRctSemanticsSimple(rv))
if (!rct::verRctSemanticsSimple(rv,
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
0
))
{
MERROR_VER("rct signature semantics check failed");
set_semantics_failed(tx_info[n].tx_hash);
@@ -976,18 +981,22 @@ namespace cryptonote
break;
}
}
if (!rvv.empty() && !rct::verRctSemanticsSimple(rvv))
if (!rvv.empty())
{
LOG_PRINT_L1("One transaction among this group has bad semantics, verifying one at a time");
ret = false;
const bool assumed_bad = rvv.size() == 1; // if there's only one tx, it must be the bad one
for (size_t n = 0; n < tx_info.size(); ++n)
{
if (!tx_info[n].result)
continue;
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus)
continue;
if (assumed_bad || !rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures))
if (!rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures,
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::CONVERT ? tx_info[n].tx->amount_burnt :
tx_info[n].tx->type == cryptonote::transaction_type::STAKE ? tx_info[n].tx->amount_burnt :
0
))
{
set_semantics_failed(tx_info[n].tx_hash);
tx_info[n].tvc.m_verifivation_failed = true;
@@ -1099,7 +1108,7 @@ namespace cryptonote
else if(tvc[i].m_verifivation_impossible)
{MERROR_VER("Transaction verification impossible: " << results[i].hash);}
if(tvc[i].m_added_to_pool)
if(tvc[i].m_added_to_pool && results[i].tx.extra.size() <= MAX_TX_EXTRA_SIZE)
{
MDEBUG("tx added: " << results[i].hash);
valid_events = true;
@@ -1502,17 +1511,18 @@ namespace cryptonote
return m_blockchain_storage.get_outs(req, res);
}
//-----------------------------------------------------------------------------------------------
bool core::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const
bool core::get_output_distribution(uint64_t amount, std::string asset_type, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base, uint64_t &num_spendable_global_outs) const
{
return m_blockchain_storage.get_output_distribution(amount, from_height, to_height, start_height, distribution, base);
MDEBUG("core::" << __func__);
return m_blockchain_storage.get_output_distribution(amount, asset_type, from_height, to_height, start_height, distribution, base, num_spendable_global_outs);
}
//-----------------------------------------------------------------------------------------------
bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const
bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<std::pair<uint64_t, uint64_t>>& indexs) const
{
return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, indexs);
}
//-----------------------------------------------------------------------------------------------
bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const
bool core::get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<std::pair<uint64_t, uint64_t>>>& indexs) const
{
return m_blockchain_storage.get_tx_outputs_gindexs(tx_id, n_txes, indexs);
}
@@ -1727,6 +1737,11 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
bool core::get_pool_transactions_info(const std::vector<crypto::hash>& txids, std::vector<std::pair<crypto::hash, tx_memory_pool::tx_details>>& txs, bool include_sensitive_txes) const
{
return m_mempool.get_transactions_info(txids, txs, include_sensitive_txes);
}
//-----------------------------------------------------------------------------------------------
bool core::get_pool_transactions(std::vector<transaction>& txs, bool include_sensitive_data) const
{
m_mempool.get_transactions(txs, include_sensitive_data);
@@ -1739,6 +1754,11 @@ namespace cryptonote
return true;
}
//-----------------------------------------------------------------------------------------------
bool core::get_pool_info(time_t start_time, bool include_sensitive_txes, size_t max_tx_count, std::vector<std::pair<crypto::hash, tx_memory_pool::tx_details>>& added_txs, std::vector<crypto::hash>& remaining_added_txids, std::vector<crypto::hash>& removed_txs, bool& incremental) const
{
return m_mempool.get_pool_info(start_time, include_sensitive_txes, max_tx_count, added_txs, remaining_added_txids, removed_txs, incremental);
}
//-----------------------------------------------------------------------------------------------
bool core::get_pool_transaction_stats(struct txpool_stats& stats, bool include_sensitive_data) const
{
m_mempool.get_transaction_stats(stats, include_sensitive_data);
+20 -3
View File
@@ -510,6 +510,23 @@ namespace cryptonote
bool get_pool_transaction_hashes(std::vector<crypto::hash>& txs, bool include_sensitive_txes = false) const;
/**
* @copydoc tx_memory_pool::get_pool_transactions_info
* @param include_sensitive_txes include private transactions
*
* @note see tx_memory_pool::get_pool_transactions_info
*/
bool get_pool_transactions_info(const std::vector<crypto::hash>& txids, std::vector<std::pair<crypto::hash, tx_memory_pool::tx_details>>& txs, bool include_sensitive_txes = false) const;
/**
* @copydoc tx_memory_pool::get_pool_info
* @param include_sensitive_txes include private transactions
* @param max_tx_count max allowed added_txs in response
*
* @note see tx_memory_pool::get_pool_info
*/
bool get_pool_info(time_t start_time, bool include_sensitive_txes, size_t max_tx_count, std::vector<std::pair<crypto::hash, tx_memory_pool::tx_details>>& added_txs, std::vector<crypto::hash>& remaining_added_txids, std::vector<crypto::hash>& removed_txs, bool& incremental) const;
/**
* @copydoc tx_memory_pool::get_transactions
* @param include_sensitive_txes include private transactions
*
@@ -588,8 +605,8 @@ namespace cryptonote
*
* @note see Blockchain::get_tx_outputs_gindexs
*/
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs) const;
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<uint64_t>>& indexs) const;
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<std::pair<uint64_t, uint64_t>>& indexs) const;
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, size_t n_txes, std::vector<std::vector<std::pair<uint64_t, uint64_t>>>& indexs) const;
/**
* @copydoc Blockchain::get_tail_id
@@ -617,7 +634,7 @@ namespace cryptonote
*
* @brief get per block distribution of outputs of a given amount
*/
bool get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const;
bool get_output_distribution(uint64_t amount, std::string asset_type, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base, uint64_t &num_spendable_global_outs) const;
/**
* @copydoc miner::pause
+629 -72
View File
@@ -1,4 +1,5 @@
// Copyright (c) 2014-2022, The Monero Project
// Portions Copyright (c) 2023-2024, Salvium (author: SRCG)
//
// All rights reserved.
//
@@ -43,11 +44,73 @@ using namespace epee;
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "ringct/rctSigs.h"
#include "oracle/asset_types.h"
using namespace crypto;
namespace cryptonote
{
rct::key sm(rct::key y, int n, const rct::key &x)
{
while (n--)
sc_mul(y.bytes, y.bytes, y.bytes);
sc_mul(y.bytes, y.bytes, x.bytes);
return y;
}
// Compute the inverse of a scalar, the clever way
rct::key invert(const rct::key &x)
{
rct::key _1, _10, _100, _11, _101, _111, _1001, _1011, _1111;
_1 = x;
sc_mul(_10.bytes, _1.bytes, _1.bytes);
sc_mul(_100.bytes, _10.bytes, _10.bytes);
sc_mul(_11.bytes, _10.bytes, _1.bytes);
sc_mul(_101.bytes, _10.bytes, _11.bytes);
sc_mul(_111.bytes, _10.bytes, _101.bytes);
sc_mul(_1001.bytes, _10.bytes, _111.bytes);
sc_mul(_1011.bytes, _10.bytes, _1001.bytes);
sc_mul(_1111.bytes, _100.bytes, _1011.bytes);
rct::key inv;
sc_mul(inv.bytes, _1111.bytes, _1.bytes);
inv = sm(inv, 123 + 3, _101);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 4, _1001);
inv = sm(inv, 2, _11);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 1 + 3, _101);
inv = sm(inv, 3 + 3, _101);
inv = sm(inv, 3, _111);
inv = sm(inv, 1 + 4, _1111);
inv = sm(inv, 2 + 3, _111);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 1 + 4, _1011);
inv = sm(inv, 2 + 4, _1011);
inv = sm(inv, 6 + 4, _1001);
inv = sm(inv, 2 + 2, _11);
inv = sm(inv, 3 + 2, _11);
inv = sm(inv, 3 + 2, _11);
inv = sm(inv, 1 + 4, _1001);
inv = sm(inv, 1 + 3, _111);
inv = sm(inv, 2 + 4, _1111);
inv = sm(inv, 1 + 4, _1011);
inv = sm(inv, 3, _101);
inv = sm(inv, 2 + 4, _1111);
inv = sm(inv, 3, _101);
inv = sm(inv, 1 + 2, _11);
// Sanity check for successful inversion
rct::key tmp;
sc_mul(tmp.bytes, inv.bytes, x.bytes);
CHECK_AND_ASSERT_THROW_MES(tmp == rct::identity(), "invert failed");
return inv;
}
//---------------------------------------------------------------
void classify_addresses(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr, size_t &num_stdaddresses, size_t &num_subaddresses, account_public_address &single_dest_subaddress)
{
@@ -75,10 +138,402 @@ namespace cryptonote
LOG_PRINT_L2("destinations include " << num_stdaddresses << " standard addresses and " << num_subaddresses << " subaddresses");
}
//---------------------------------------------------------------
bool get_return_address(const size_t tx_version, // needed in case we change implementation down the line
const cryptonote::transaction_type& tx_type, // needed because TRANSFER needs to use F point instead of return_address and TX pubkey
const crypto::ec_scalar& y,
const cryptonote::account_keys &sender_account_keys, // needed to calculate pretty much anything
const crypto::public_key &P_change, // one-time public key from CONVERT/YIELD change
const crypto::public_key &txkey_pub, // public TX key from CONVERT/YIELD TX
crypto::public_key& F, // OUTPUT return address OTPK
crypto::public_key& F_txkey_pub, // OUTPUT TX pub key
hw::device& hwdev // hardware device to use (usually a software dev)
) {
LOG_ERROR("Cryptonote::" << __func__ << ":" << __LINE__);
LOG_ERROR("Break here");
// Now generate the return address EC point
// F = (y^-1).a.P_change
// First, we need to produce the multiplicative inverse of the scalar "y" (aka "y^-1")
rct::key key_y = (rct::key&)(y);
rct::key key_inv_y = invert(key_y);
crypto::public_key pk_aP_change = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(sender_account_keys.m_view_secret_key)));
// Sanity check that we can reverse the invert safely
rct::key key_aP_change = rct::pk2rct(pk_aP_change);
rct::key key_F = rct::scalarmultKey(key_aP_change, key_inv_y);
rct::key key_verify = rct::scalarmultKey(key_F, key_y);
CHECK_AND_ASSERT_MES(key_verify == key_aP_change, false, "at get_return_address: failed to verify invert() function with smK() approach");
if (tx_type == cryptonote::transaction_type::TRANSFER) {
// Store the F point - we do not need to generate a full return address in this instance
F = rct::rct2pk(key_F);
// Clear the pubkey, because it isn't used
F_txkey_pub = crypto::null_pkey;
/*
// SANITY CHECK - PERFORM --ALL-- THE STEPS REQUIRED TO VERIFY THIS PROCESS WILL WORK
crypto::secret_key s = keypair::generate(hw::get_device("default")).sec;
crypto::key_derivation derivation_syF = AUTO_VAL_INIT(derivation_syF);
bool r = hwdev.generate_key_derivation(rct::rct2pk(key_aP_change), s, derivation_syF);
crypto::public_key onetime = crypto::null_pkey;
r = hwdev.derive_public_key(derivation_syF, 0, P_change, onetime);
crypto::public_key R = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(s)));
crypto::key_derivation derivation_ret = AUTO_VAL_INIT(derivation_ret);
r = hwdev.generate_key_derivation(R, sender_account_keys.m_view_secret_key, derivation_ret);
crypto::public_key P_change_ver = crypto::null_pkey;
r = hwdev.derive_subaddress_public_key(onetime, derivation_ret, 0, P_change_ver);
CHECK_AND_ASSERT_MES(P_change == P_change_ver, false, "at get_return_address: failed to verify ALL steps");
LOG_ERROR("*****************************************************************************");
LOG_ERROR("TX type : TRANSFER");
LOG_ERROR("txkey_pub : " << txkey_pub);
LOG_ERROR("a : " << sender_account_keys.m_view_secret_key);
LOG_ERROR("y : " << key_y);
LOG_ERROR("P_change : " << P_change);
LOG_ERROR("aP_change : " << pk_aP_change);
LOG_ERROR("F : " << F);
LOG_ERROR("*****************************************************************************");
*/
// We are done here - return to caller
return true;
} else if (tx_type == cryptonote::transaction_type::STAKE) {
// CONVERT / YIELD Semantics
// From this point forward, we are departing from the original "return address" scheme
// We have to derive the full return address and TX pubkey, because PROTOCOL_TX cannot
// First, create a secret TX key (= s) - this will be lost at the end of this function, but that's OK
crypto::secret_key s = keypair::generate(hw::get_device("default")).sec;
// Next, calculate the corresponding TX public key (= sP_change)
// This has to be done using smK() call because of g_k_d() performing a torsion clear
F_txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(s)));
// Next, calculate a derivation using the TX public key and our secret view key
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
bool r = hwdev.generate_key_derivation(F_txkey_pub, sender_account_keys.m_view_secret_key, derivation);
CHECK_AND_ASSERT_MES(r, false, "in get_return_address(): failed to generate_key_derivation(" << F_txkey_pub << ", <view secret key>)");
// Finally, calculate the onetime address to be used for returns
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
r = crypto::derive_public_key(derivation, 0, P_change, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "in get_return_address(): failed to derive_public_key(" << derivation << ", " << key_y << ", "<< P_change << ")");
// Sanity checks
crypto::public_key P_change_verify = crypto::null_pkey;
r = crypto::derive_subaddress_public_key(out_eph_public_key, derivation, 0, P_change_verify);
CHECK_AND_ASSERT_MES(r, false, "in get_return_address(): failed sanity check derive_subaddress_public_key(" << out_eph_public_key << ", " << derivation << ", " << key_y << ", " << P_change_verify << ")");
CHECK_AND_ASSERT_MES(P_change == P_change_verify, false, "in get_return_address(): failed sanity check (keys do not match)");
// All is well - copy the return address
F = out_eph_public_key;
/*
LOG_ERROR("*****************************************************************************");
LOG_ERROR("txkey_pub : " << txkey_pub);
LOG_ERROR("a : " << sender_account_keys.m_view_secret_key);
LOG_ERROR("s : " << s);
LOG_ERROR("y : " << key_y);
LOG_ERROR("P_change : " << P_change);
LOG_ERROR("aP_change : " << pk_aP_change);
LOG_ERROR("F : " << F);
LOG_ERROR("*****************************************************************************");
*/
// We are done here - return to caller
return true;
}
// Not implemented yet
return false;
}
//---------------------------------------------------------------
bool get_conversion_rate(const oracle::pricing_record& pr, const std::string& from_asset, const std::string& to_asset, uint64_t& rate) {
// Check for burns
if (to_asset == "BURN") {
LOG_ERROR("Converting to a BURN is nonsensical - aborting");
rate = std::numeric_limits<uint64_t>::max();
return false;
}
// Check for transfers
if (from_asset == to_asset) {
rate = COIN;
return true;
}
if ((from_asset == "SAL" && to_asset != "VSD") ||
(from_asset == "VSD" && to_asset != "SAL")) {
// Invalid conversion - abort
LOG_ERROR("Invalid conversion (" << from_asset << "," << to_asset << ") - aborting");
return false;
}
// Scale to correct value
boost::multiprecision::uint128_t rate_128 = COIN;
rate_128 *= pr[from_asset];
rate_128 /= pr[to_asset];
rate = rate_128.convert_to<uint64_t>();
rate -= (rate % 10000);
return true;
}
//---------------------------------------------------------------
bool get_converted_amount(const uint64_t& conversion_rate, const uint64_t& source_amount, uint64_t& dest_amount) {
if (!conversion_rate || !source_amount) {
LOG_ERROR("Invalid conversion rate or input amount for conversion (" << conversion_rate << "," << source_amount << ") - aborting");
return false;
}
boost::multiprecision::uint128_t source_amount_128 = source_amount;
boost::multiprecision::uint128_t conversion_rate_128 = conversion_rate;
boost::multiprecision::uint128_t dest_amount_128 = source_amount_128 * conversion_rate_128;
dest_amount_128 /= COIN;
dest_amount = dest_amount_128.convert_to<uint64_t>();
return true;
}
//---------------------------------------------------------------
bool calculate_conversion(const std::string& source_asset, const std::string& dest_asset, const uint64_t amount_burnt, const uint64_t amount_slippage_limit, uint64_t& amount_minted, uint64_t& amount_slippage, const std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const uint8_t hf_version) {
// Sanity check - are the asset types a valid conversion?
CHECK_AND_ASSERT_MES(source_asset != dest_asset, false, "cannot calculate slippage when source and dest assets are identical");
CHECK_AND_ASSERT_MES(source_asset != "", false, "source_asset not provided");
CHECK_AND_ASSERT_MES(dest_asset != "", false, "dest_asset not provided (is this a BURN?)");
/////CHECK_AND_ASSERT_MES(pr.has_rate(dest_asset), false, "missing rate for " << dest_asset <<" in pricing record - cannot calculate conversion");
CHECK_AND_ASSERT_MES(circ_supply.count(source_asset) != 0, false, "missing circulating_supply data - cannot calculate slippage");
// Get the conversion rate for the TX
uint64_t conversion_rate = COIN;
bool ok = get_conversion_rate(pr, source_asset, dest_asset, conversion_rate);
CHECK_AND_ASSERT_MES(ok, false, "Unable to get conversion rate for " << source_asset << " to " << dest_asset);
// Apply slippage to the burnt amount
amount_slippage = amount_burnt >> 5; // (1/32)
// Check that the slippage is acceptable
if (amount_slippage > amount_slippage_limit) {
// Bail out with no conversion
LOG_PRINT_L1("Unable to convert - slippage limit was too low");
amount_minted = 0;
return true;
}
// Work out the converted amount
ok = get_converted_amount(conversion_rate, amount_burnt - amount_slippage, amount_minted);
CHECK_AND_ASSERT_MES(ok, false, "Unable to get converted amount for " << (amount_burnt - amount_slippage) << ", converting from " << source_asset << " to " << dest_asset);
return true;
}
//---------------------------------------------------------------
bool construct_protocol_tx(const size_t height,
uint64_t& protocol_fee,
transaction& tx,
std::vector<protocol_data_entry>& protocol_data,
std::map<std::string, uint64_t> circ_supply,
const oracle::pricing_record& pr,
const account_public_address &miner_address,
const account_public_address &treasury_address,
const uint8_t hf_version) {
// A vector to contain all of the additional _tx_secret_keys_
//std::vector<crypto::secret_key>& additional_tx_keys;
// Clear the TX contents
tx.set_null();
tx.type = cryptonote::transaction_type::PROTOCOL;
// Force the TX type to 2
tx.version = 2;
keypair txkey = keypair::generate(hw::get_device("default"));
add_tx_pub_key_to_extra(tx, txkey.pub);
if (!sort_tx_extra(tx.extra, tx.extra))
return false;
// Update the circulating_supply information, while keeping a count of amount to be created using txin_gen
std::map<std::string, uint64_t> txin_gen_totals;
uint64_t txin_gen_final = 0;
for (auto const& entry: protocol_data) {
if (!circ_supply.count(entry.source_asset)) {
LOG_ERROR("Circulating supply does not have " << entry.source_asset << " balance - invalid source_asset");
return false;
}
// Deduct the amount_burnt from the circulating_supply balance
circ_supply[entry.source_asset] -= entry.amount_burnt;
}
// Calculate the slippage for the output amounts
LOG_PRINT_L2("Creating protocol_tx...");
uint64_t slippage_total = 0;
std::vector<crypto::public_key> additional_tx_public_keys;
for (auto const& entry: protocol_data) {
if (entry.destination_asset == "BURN") {
// BURN TX - no slippage, no money minted - skip
continue;
}
// CONVERT TX
/*
// Create a secret TX key (= s)
crypto::secret_key s = keypair::generate(hw::get_device("default")).sec;
//additional_tx_keys.push_back(s);
// Now add the correct TX public key (= sP_change)
// This has to be done using smK() call because of g_k_d() performing a torsion clear
crypto::public_key txkey_pub = rct::rct2pk(rct::scalarmultKey(rct::pk2rct(entry.P_change), rct::sk2rct(s)));
additional_tx_public_keys.push_back(txkey_pub);
// Calculate the actual return address, because the field we already have is actually the TX pubkey to use
// return address = Hs(syF || i)G + P_change = Hs(saP_change || i)G + P_change
// Generate the uniqueness for the input
size_t output_index = tx.vout.size();
// y = Hs(uniqueness)
ec_scalar y;
CHECK_AND_ASSERT_MES(cryptonote::calculate_uniqueness((cryptonote::transaction_type)(entry.type), entry.input_k_image, height, 0, y), false, "while creating protocol_tx outs: failed to calculate uniqueness");
rct::key key_y = (rct::key&)(y);
rct::key key_F = (rct::key&)(entry.return_address);
crypto::public_key syF = rct::rct2pk(rct::scalarmultKey(rct::scalarmultKey(key_F, key_y), rct::sk2rct(s)));
crypto::key_derivation derivation_syF = AUTO_VAL_INIT(derivation_syF);
std::memcpy(derivation_syF.data, syF.data, sizeof(crypto::key_derivation));
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
bool r = crypto::derive_public_key(derivation_syF, output_index, entry.P_change, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed to derive_public_key(" << derivation_syF << ", " << key_y << ", "<< entry.P_change << ")");
// Sanity checks
crypto::public_key P_change_verify = crypto::null_pkey;
r = crypto::derive_subaddress_public_key(out_eph_public_key, derivation_syF, output_index, P_change_verify);
CHECK_AND_ASSERT_MES(r, false, "while creating protocol_tx outs: failed sanity check calling derive_subaddress_public_key(" << out_eph_public_key << ", " << derivation_syF << ", " << key_y << ", " << P_change_verify << ")");
CHECK_AND_ASSERT_MES(entry.P_change == P_change_verify, false, "while creating protocol_tx outs: failed sanity check (keys do not match)");
*/
/*
LOG_ERROR("***************************************************************************************");
LOG_ERROR("output_index : " << output_index);
LOG_ERROR("P_change : " << entry.P_change);
LOG_ERROR("key_y : " << key_y);
LOG_ERROR("key_F : " << key_F);
LOG_ERROR("s : " << s);
LOG_ERROR("der. (syF) : " << derivation_syF);
LOG_ERROR("txkey_pub : " << txkey_pub);
LOG_ERROR("output_key : " << out_eph_public_key << " (derivation_syF, output_index, P_change)");
LOG_ERROR("P_change_ver : " << P_change_verify);
LOG_ERROR("***************************************************************************************");
*/
if (entry.type == cryptonote::transaction_type::CONVERT) {
// Now calculate the slippage, and decide if it is going to be converted or refunded
uint64_t amount_slippage = 0, amount_minted = 0;
bool ok = cryptonote::calculate_conversion(entry.source_asset, entry.destination_asset, entry.amount_burnt, entry.amount_slippage_limit, amount_minted, amount_slippage, circ_supply, pr, hf_version);
if (!ok) {
LOG_ERROR("failed to calculate slippage when trying to build protocol_tx");
return false;
}
if (amount_minted == 0) {
// REFUND
LOG_PRINT_L2("Conversion TX refunded - slippage too high");
txin_gen_totals[entry.source_asset] += entry.amount_burnt;
// Create the TX output for this refund
tx_out out;
//cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
} else {
// CONVERTED
LOG_PRINT_L2("Conversion TX submitted - converted " << print_money(entry.amount_burnt) << " " << entry.source_asset << " to " << print_money(amount_minted) << " " << entry.destination_asset << "(slippage " << print_money(amount_slippage) << ")");
txin_gen_totals[entry.destination_asset] += amount_minted;
// Add the slippage to our total for the block
if (entry.source_asset == "SAL") {
slippage_total += amount_slippage;
} else {
// Convert the slippage into a SAL amount so we can pay a proportion to the miner
uint64_t conversion_rate = 0, amount_slippage_converted = 0;
ok = get_conversion_rate(pr, entry.source_asset, entry.destination_asset, conversion_rate);
CHECK_AND_ASSERT_MES(ok, false, "Failed to get conversion rate for miner payout");
ok = get_converted_amount(conversion_rate, amount_slippage, amount_slippage_converted);
CHECK_AND_ASSERT_MES(ok, false, "Failed to get converted slippage amount for miner payout");
slippage_total += amount_slippage_converted;
}
// Create the TX output for this conversion
tx_out out;
//cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(amount_minted, entry.destination_asset, 0, 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::STAKE) {
// PAYOUT
LOG_PRINT_L2("Yield TX payout submitted " << entry.amount_burnt << entry.source_asset);
txin_gen_totals[entry.source_asset] += entry.amount_burnt;
// Create the TX output for this refund
tx_out out;
//cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, out_eph_public_key, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(entry.amount_burnt, entry.source_asset, 0, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
}
}
// Add in all of the additional TX pubkeys we need to process the payments
add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys);
if (slippage_total > 0) {
// Add a payout for the miner
uint64_t slippage_miner = slippage_total / 5;
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
r = crypto::derive_public_key(derivation, tx.vout.size(), miner_address.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
tx_out out_miner;
cryptonote::set_tx_out(slippage_miner, "SAL", 0, out_eph_public_key, false, crypto::view_tag{}, out_miner);
tx.vout.push_back(out_miner);
// Add a payout for the treasury
crypto::key_derivation derivation_treasury = AUTO_VAL_INIT(derivation_treasury);
crypto::public_key out_eph_public_key_treasury = AUTO_VAL_INIT(out_eph_public_key_treasury);
r = crypto::generate_key_derivation(treasury_address.m_view_public_key, txkey.sec, derivation_treasury);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << treasury_address.m_view_public_key << ", " << txkey.sec << ")");
r = crypto::derive_public_key(derivation_treasury, tx.vout.size(), treasury_address.m_spend_public_key, out_eph_public_key_treasury);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
uint64_t slippage_treasury = slippage_miner >> 1;
tx_out out_treasury;
cryptonote::set_tx_out(slippage_treasury, "SAL", 0, out_eph_public_key_treasury, false, crypto::view_tag{}, out_treasury);
tx.vout.push_back(out_treasury);
}
// Create the txin_gen now
txin_gen in;
in.height = height;
tx.vin.push_back(in);
return true;
}
//---------------------------------------------------------------
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) {
tx.vin.clear();
tx.vout.clear();
tx.extra.clear();
// Clear the TX contents
tx.set_null();
tx.type = cryptonote::transaction_type::MINER;
keypair txkey = keypair::generate(hw::get_device("default"));
add_tx_pub_key_to_extra(tx, txkey.pub);
@@ -103,75 +558,56 @@ namespace cryptonote
", fee " << fee);
#endif
block_reward += fee;
// from hard fork 2, we cut out the low significant digits. This makes the tx smaller, and
// keeps the paid amount almost the same. The unpaid remainder gets pushed back to the
// emission schedule
// from hard fork 4, we use a single "dusty" output. This makes the tx even smaller,
// and avoids the quantization. These outputs will be added as rct outputs with identity
// masks, to they can be used as rct inputs.
if (hard_fork_version >= 2 && hard_fork_version < 4) {
block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD;
}
std::vector<uint64_t> out_amounts;
decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::DEFAULT_DUST_THRESHOLD,
[&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); },
[&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
if (height == 0 || hard_fork_version >= 4)
{
// the genesis block was not decomposed, for unknown reasons
while (max_outs < out_amounts.size())
{
//out_amounts[out_amounts.size() - 2] += out_amounts.back();
//out_amounts.resize(out_amounts.size() - 1);
out_amounts[1] += out_amounts[0];
for (size_t n = 1; n < out_amounts.size(); ++n)
out_amounts[n - 1] = out_amounts[n];
out_amounts.pop_back();
}
}
else
{
CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded");
}
uint64_t summary_amounts = 0;
for (size_t no = 0; no < out_amounts.size(); no++)
{
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
r = crypto::derive_public_key(derivation, no, miner_address.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << no << ", "<< miner_address.m_spend_public_key << ")");
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key);
bool r = crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << txkey.sec << ")");
uint64_t amount = out_amounts[no];
summary_amounts += amount;
r = crypto::derive_public_key(derivation, 0, miner_address.m_spend_public_key, out_eph_public_key);
CHECK_AND_ASSERT_MES(r, false, "while creating outs: failed to derive_public_key(" << derivation << ", " << 0 << ", "<< miner_address.m_spend_public_key << ")");
uint64_t amount = block_reward;
summary_amounts += amount;
bool use_view_tags = hard_fork_version >= HF_VERSION_VIEW_TAGS;
crypto::view_tag view_tag;
if (use_view_tags)
crypto::derive_view_tag(derivation, no, view_tag);
crypto::derive_view_tag(derivation, 0, view_tag);
// Should we award some of the block reward to the stakers?
if (height != 0) {
// Different forks take a different proportion of the block_reward for stakers
switch (hard_fork_version) {
case HF_VERSION_BULLETPROOF_PLUS:
// SRCG: subtract 20% that will be rewarded to staking users
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
tx.amount_burnt = amount / 5;
amount -= tx.amount_burnt;
break;
default:
assert(false);
}
tx_out out;
cryptonote::set_tx_out(amount, out_eph_public_key, use_view_tags, view_tag, out);
cryptonote::set_tx_out(amount, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
tx.vout.push_back(out);
} else {
// Genesis TX - create the necessary distribution for Salvium seed funds
tx_out out;
cryptonote::set_tx_out(PREMINE_AMOUNT, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
tx.vout.push_back(out);
}
CHECK_AND_ASSERT_MES(summary_amounts == block_reward, false, "Failed to construct miner tx, summary_amounts = " << summary_amounts << " not equal block_reward = " << block_reward);
if (hard_fork_version >= 4)
tx.version = 2;
else
tx.version = 1;
tx.version = 2;
//lock
tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW;
tx.vin.push_back(in);
tx.invalidate_hashes();
@@ -203,7 +639,7 @@ namespace cryptonote
return addr.m_view_public_key;
}
//---------------------------------------------------------------
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags)
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags)
{
hw::device &hwdev = sender_account_keys.get_device();
@@ -217,12 +653,20 @@ namespace cryptonote
tx.set_null();
amount_keys.clear();
tx.version = rct ? 2 : 1;
tx.unlock_time = unlock_time;
if (hf_version >= HF_VERSION_SLIPPAGE_YIELD) {
tx.version = 3;
} else {
tx.version = 2;
}
tx.extra = extra;
crypto::public_key txkey_pub;
tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
tx.source_asset_type = source_asset;
tx.destination_asset_type = dest_asset;
// if we have a stealth payment id, find it and encrypt it with the tx key now
std::vector<tx_extra_field> tx_extra_fields;
if (parse_tx_extra(tx.extra, tx_extra_fields))
@@ -323,7 +767,8 @@ namespace cryptonote
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
crypto::key_image img;
const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev))
bool use_origin_data = (src_entr.origin_tx_data.tx_type != cryptonote::transaction_type::UNSET);
if(!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, in_ephemeral,img, hwdev, use_origin_data, src_entr.origin_tx_data))
{
LOG_ERROR("Key image generation failed!");
return false;
@@ -344,7 +789,8 @@ namespace cryptonote
txin_to_key input_to_key;
input_to_key.amount = src_entr.amount;
input_to_key.k_image = img;
input_to_key.asset_type = src_entr.asset_type;
//fill outputs array and use relative offsets
for(const tx_source_entry::output_entry& out_entry: src_entr.outputs)
input_to_key.key_offsets.push_back(out_entry.first);
@@ -396,19 +842,50 @@ namespace cryptonote
// we don't need to include additional tx keys if:
// - all the destinations are standard addresses
// - there's only one destination which is a subaddress
bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1);
bool need_additional_txkeys = tx_type == cryptonote::RETURN || (num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1));
if (need_additional_txkeys)
CHECK_AND_ASSERT_MES(destinations.size() == additional_tx_keys.size(), false, "Wrong amount of additional tx keys");
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = 0;
size_t change_index = 0;
for(const tx_destination_entry& dst_entr: destinations)
{
CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount);
crypto::public_key out_eph_public_key;
crypto::view_tag view_tag;
// Is this a BURN or CONVERT TX?
if (tx_type == cryptonote::transaction_type::BURN || tx_type == cryptonote::transaction_type::CONVERT) {
// Do not create outputs that are for the destination asset type - discard them as unused
if (dst_entr.asset_type == dest_asset) {
tx.amount_burnt += dst_entr.amount;
tx.amount_slippage_limit = dst_entr.slippage_limit;
continue;
}
} else if (tx_type == cryptonote::transaction_type::STAKE) {
// Do not create outputs that are staked for yield - discard them as unused
if (!dst_entr.is_change) {
tx.amount_burnt += dst_entr.amount;
continue;
}
}
// Check to see if this is the change output
if (dst_entr.is_change) {
change_index = output_index;
}
LOG_ERROR("*****************************************************************************");
LOG_ERROR("in construct_tx_With_tx_key()");
LOG_ERROR("TX type : TRANSFER");
LOG_ERROR("tx_key : " << tx_key);
LOG_ERROR("tx_pubkey : " << txkey_pub);
LOG_ERROR("P_change : " << dst_entr.addr.m_spend_public_key);
LOG_ERROR("aP_change : " << dst_entr.addr.m_view_public_key);
LOG_ERROR("*****************************************************************************");
hwdev.generate_output_ephemeral_keys(tx.version,sender_account_keys, txkey_pub, tx_key,
dst_entr, change_addr, output_index,
need_additional_txkeys, additional_tx_keys,
@@ -416,7 +893,7 @@ namespace cryptonote
use_view_tags, view_tag);
tx_out out;
cryptonote::set_tx_out(dst_entr.amount, out_eph_public_key, use_view_tags, view_tag, out);
cryptonote::set_tx_out(dst_entr.amount, dst_entr.asset_type, dst_entr.is_change ? 0 : unlock_time, out_eph_public_key, use_view_tags, view_tag, out);
tx.vout.push_back(out);
output_index++;
summary_outs_money += dst_entr.amount;
@@ -425,6 +902,32 @@ namespace cryptonote
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys));
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE) {
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
if (tx.type == cryptonote::transaction_type::TRANSFER)
CHECK_AND_ASSERT_MES(tx.vout.size() == 2, false, "Internal error - incorrect number of outputs (!=2) for TRANSFER tx");
else if (tx.type == cryptonote::transaction_type::STAKE)
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for YIELD tx");
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
// Get the uniqueness for this TX
ec_scalar y;
struct {
char domain_separator[8];
crypto::public_key pubkey;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 6);
buf.pubkey = P_change;
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// Now generate the return address and TX pubkey
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, y, sender_account_keys, P_change, txkey_pub, tx.return_address, tx.return_pubkey, hwdev), false, "Failed to get protocol destination address");
}
LOG_PRINT_L2("tx pubkey: " << txkey_pub);
if (need_additional_txkeys)
{
@@ -526,6 +1029,7 @@ namespace cryptonote
rct::ctkeyM mixRing(use_simple_rct ? sources.size() : n_total_outs);
rct::keyV destinations;
std::vector<uint64_t> inamounts, outamounts;
std::vector<std::string> destination_asset_types;
std::vector<unsigned int> index;
for (size_t i = 0; i < sources.size(); ++i)
{
@@ -544,8 +1048,19 @@ namespace cryptonote
for (size_t i = 0; i < tx.vout.size(); ++i)
{
crypto::public_key output_public_key;
get_output_public_key(tx.vout[i], output_public_key);
bool ok = get_output_public_key(tx.vout[i], output_public_key);
if (!ok) {
LOG_ERROR("failed to get output public key for tx.vout[" << i << "]");
return false;
}
std::string output_asset_type;
ok = cryptonote::get_output_asset_type(tx.vout[i], output_asset_type);
if (!ok) {
LOG_ERROR("failed to get output asset type for tx.vout[" << i << "]");
return false;
}
destinations.push_back(rct::pk2rct(output_public_key));
destination_asset_types.push_back(output_asset_type);
outamounts.push_back(tx.vout[i].amount);
amount_out += tx.vout[i].amount;
}
@@ -575,8 +1090,11 @@ namespace cryptonote
}
// fee
uint64_t fee = 0;
if (!use_simple_rct && amount_in > amount_out)
outamounts.push_back(amount_in - amount_out);
else
fee = summary_inputs_money - summary_outs_money - tx.amount_burnt;
// zero out all amounts to mask rct outputs, real amounts are now encrypted
for (size_t i = 0; i < tx.vin.size(); ++i)
@@ -584,14 +1102,51 @@ namespace cryptonote
if (sources[i].rct)
boost::get<txin_to_key>(tx.vin[i]).amount = 0;
}
for (size_t i = 0; i < tx.vout.size(); ++i)
tx.vout[i].amount = 0;
std::vector<bool> zero_masks;
zero_masks.reserve(tx.vout.size());
for (size_t i = 0; i < tx.vout.size(); ++i) {
if (tx.type == cryptonote::transaction_type::STAKE) {
uint64_t unlock_time = 0;
bool ok = get_output_unlock_time(tx.vout[i], unlock_time);
if (!ok) {
LOG_ERROR("failed to get output asset type for tx.vout[" << i << "]");
return false;
}
if (unlock_time == 0) {
zero_masks.emplace_back(false);
} else {
zero_masks.emplace_back(true);
}
} else {
zero_masks.emplace_back(false);
}
// Clear the amount in the output
tx.vout[i].amount = 0;
}
crypto::hash tx_prefix_hash;
get_transaction_prefix_hash(tx, tx_prefix_hash, hwdev);
rct::ctkeyV outSk;
if (use_simple_rct)
tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, index, outSk, rct_config, hwdev);
tx.rct_signatures = rct::genRctSimple(
rct::hash2rct(tx_prefix_hash),
inSk,
destinations,
tx_type,
source_asset,
destination_asset_types,
zero_masks,
inamounts,
outamounts,
fee,
mixRing,
amount_keys,
index,
outSk,
rct_config,
hwdev
);
else
tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, sources[0].real_output, outSk, rct_config, hwdev); // same index assumption
memwipe(inSk.data(), inSk.size() * sizeof(rct::ctkey));
@@ -606,7 +1161,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool use_view_tags)
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool use_view_tags)
{
hw::device &hwdev = sender_account_keys.get_device();
hwdev.open_tx(tx_key);
@@ -616,7 +1171,7 @@ namespace cryptonote
size_t num_subaddresses = 0;
account_public_address single_dest_subaddress;
classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress);
bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1);
bool need_additional_txkeys = tx_type == cryptonote::RETURN || (num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1));
if (need_additional_txkeys)
{
additional_tx_keys.clear();
@@ -627,7 +1182,7 @@ namespace cryptonote
}
bool shuffle_outs = true;
bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, shuffle_outs, use_view_tags);
bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, hf_version, source_asset, dest_asset, tx_type, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, shuffle_outs, use_view_tags);
hwdev.close_tx();
return r;
} catch(...) {
@@ -636,14 +1191,14 @@ namespace cryptonote
}
}
//---------------------------------------------------------------
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time)
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& asset_type, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time)
{
std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses;
subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0};
crypto::secret_key tx_key;
std::vector<crypto::secret_key> additional_tx_keys;
std::vector<tx_destination_entry> destinations_copy = destinations;
return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0});
return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, hf_version, asset_type, asset_type, tx_type, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0});
}
//---------------------------------------------------------------
bool generate_genesis_block(
@@ -654,6 +1209,8 @@ namespace cryptonote
{
//genesis block
bl = {};
bl.protocol_tx.set_null();
bl.protocol_tx.type = cryptonote::transaction_type::PROTOCOL;
blobdata tx_bl;
bool r = string_tools::parse_hexstr_to_binbuff(genesis_tx, tx_bl);
+60 -8
View File
@@ -1,4 +1,5 @@
// Copyright (c) 2014-2022, The Monero Project
// Portions Copyright (c) 2023-2024, Salvium (author: SRCG)
//
// All rights reserved.
//
@@ -33,9 +34,40 @@
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include "ringct/rctOps.h"
#include "oracle/pricing_record.h"
#include "cryptonote_protocol/enums.h"
namespace cryptonote
{
bool get_conversion_rate(const oracle::pricing_record& pr, const std::string& from_asset, const std::string& to_asset, uint64_t& rate);
bool get_converted_amount(const uint64_t& conversion_rate, const uint64_t& source_amount, uint64_t& dest_amount);
bool calculate_conversion(const std::string& source_asset, const std::string& dest_asset, const uint64_t amount_burnt, const uint64_t amount_slippage_limit, uint64_t& amount_minted, uint64_t& amount_slippage, const std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const uint8_t hf_version);
//---------------------------------------------------------------
/**
* Construct the protocol_tx
*
* @param height the current blockchain height (for reasons unknown)
* @param protocol_fee a variable that will receive the total supplementary fee due to be assigned to the block reward
* @param tx the actual TX instance to be populated with the necessary txin_gen and txout_to_key entries etc
* @param hf_version the current hard-fork version of the blockchain
*
* @return TRUE on success, FALSE otherwise (duh)
*/
struct protocol_data_entry
{
crypto::public_key return_address;
uint64_t amount_burnt;
uint64_t amount_minted;
uint64_t amount_slippage_limit;
std::string source_asset;
std::string destination_asset;
uint8_t type;
crypto::public_key P_change;
crypto::public_key return_pubkey;
};
//---------------------------------------------------------------
bool construct_protocol_tx(const size_t height, uint64_t& protocol_fee, transaction& tx, std::vector<protocol_data_entry>& protocol_data, std::map<std::string, uint64_t> circ_supply, const oracle::pricing_record& pr, const account_public_address &miner_address, const account_public_address &treasury_address, const uint8_t hf_version);
//---------------------------------------------------------------
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
@@ -52,6 +84,8 @@ namespace cryptonote
bool rct; //true if the output is rct
rct::key mask; //ringct amount mask
rct::multisig_kLRki multisig_kLRki; //multisig info
std::string asset_type;
origin_data origin_tx_data;
void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); }
@@ -65,7 +99,9 @@ namespace cryptonote
FIELD(rct)
FIELD(mask)
FIELD(multisig_kLRki)
FIELD(asset_type)
FIELD(origin_tx_data)
if (real_output >= outputs.size())
return false;
END_SERIALIZE()
@@ -75,14 +111,26 @@ namespace cryptonote
{
std::string original;
uint64_t amount; //money
uint64_t slippage_limit; //percentage of slippage permitted
account_public_address addr; //destination address
std::string asset_type;
bool is_subaddress;
bool is_integrated;
bool is_change;
bool is_return;
tx_destination_entry() : amount(0), addr(AUTO_VAL_INIT(addr)), is_subaddress(false), is_integrated(false) { }
tx_destination_entry(uint64_t a, const account_public_address &ad, bool is_subaddress) : amount(a), addr(ad), is_subaddress(is_subaddress), is_integrated(false) { }
tx_destination_entry(const std::string &o, uint64_t a, const account_public_address &ad, bool is_subaddress) : original(o), amount(a), addr(ad), is_subaddress(is_subaddress), is_integrated(false) { }
tx_destination_entry() : amount(0), slippage_limit(0), addr(AUTO_VAL_INIT(addr)), is_subaddress(false), is_integrated(false), is_change(false), is_return(false) { }
tx_destination_entry(uint64_t a, const account_public_address &ad, bool is_subaddress) : amount(a), slippage_limit(0), addr(ad), is_subaddress(is_subaddress), is_integrated(false), is_change(false), is_return(false) { }
tx_destination_entry(uint64_t a, const account_public_address &ad, bool is_subaddress, bool is_return) : amount(a), slippage_limit(0), addr(ad), is_subaddress(is_subaddress), is_integrated(false), is_change(false), is_return(is_return) { }
tx_destination_entry(const std::string &o, uint64_t a, const account_public_address &ad, bool is_subaddress) : original(o), amount(a), slippage_limit(0), addr(ad), is_subaddress(is_subaddress), is_integrated(false), is_change(false), is_return(false) { }
tx_destination_entry(const std::string &o, uint64_t a, const account_public_address &ad, bool is_subaddress, bool is_return) : original(o), amount(a), slippage_limit(0), addr(ad), is_subaddress(is_subaddress), is_integrated(false), is_change(false), is_return(is_return) { }
/*
tx_destination_entry() : amount(0), addr(AUTO_VAL_INIT(addr)), is_subaddress(false), is_integrated(false), is_change(false), is_return(false) { }
tx_destination_entry(uint64_t a, const account_public_address &ad, bool is_subaddress) : amount(a), addr(ad), is_subaddress(is_subaddress), is_integrated(false), is_change(false), is_return(false) { }
tx_destination_entry(uint64_t a, const account_public_address &ad, bool is_subaddress, bool is_return) : amount(a), addr(ad), is_subaddress(is_subaddress), is_integrated(false), is_change(false), is_return(is_return) { }
tx_destination_entry(const std::string &o, uint64_t a, const account_public_address &ad, bool is_subaddress) : original(o), amount(a), addr(ad), is_subaddress(is_subaddress), is_integrated(false), is_change(false), is_return(false) { }
tx_destination_entry(const std::string &o, uint64_t a, const account_public_address &ad, bool is_subaddress, bool is_return) : original(o), amount(a), addr(ad), is_subaddress(is_subaddress), is_integrated(false), is_change(false), is_return(is_return) { }
*/
std::string address(network_type nettype, const crypto::hash &payment_id) const
{
if (!original.empty())
@@ -104,6 +152,8 @@ namespace cryptonote
FIELD(addr)
FIELD(is_subaddress)
FIELD(is_integrated)
FIELD(is_change)
FIELD(is_return)
END_SERIALIZE()
};
@@ -118,9 +168,11 @@ namespace cryptonote
//---------------------------------------------------------------
crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr);
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time);
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false);
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false);
bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& asset_type, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time);
bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false);
bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const uint8_t hf_version, const std::string& source_asset, const std::string& dest_asset, const cryptonote::transaction_type& tx_type, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false);
bool generate_output_ephemeral_keys(const size_t tx_version, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key,
const cryptonote::tx_destination_entry &dst_entr, const boost::optional<cryptonote::account_public_address> &change_addr, const size_t output_index,
const bool &need_additional_txkeys, const std::vector<crypto::secret_key> &additional_tx_keys,
+268 -32
View File
@@ -133,6 +133,12 @@ namespace cryptonote
// class code expects unsigned values throughout
if (m_next_check < time_t(0))
throw std::runtime_error{"Unexpected time_t (system clock) value"};
m_added_txs_start_time = (time_t)0;
m_removed_txs_start_time = (time_t)0;
// We don't set these to "now" already here as we don't know how long it takes from construction
// of the pool until it "goes to work". It's safer to set when the first actual txs enter the
// corresponding lists.
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, const cryptonote::blobdata &blob, size_t tx_weight, tx_verification_context& tvc, relay_method tx_relay, bool relayed, uint8_t version)
@@ -207,6 +213,7 @@ namespace cryptonote
{
tvc.m_verifivation_failed = true;
tvc.m_fee_too_low = true;
tvc.m_no_drop_offense = true;
return false;
}
@@ -225,6 +232,7 @@ namespace cryptonote
LOG_PRINT_L1("transaction tx-extra is too big: " << tx_extra_size << " bytes, the limit is: " << MAX_TX_EXTRA_SIZE);
tvc.m_verifivation_failed = true;
tvc.m_tx_extra_too_big = true;
tvc.m_no_drop_offense = true;
return false;
}
@@ -239,6 +247,7 @@ namespace cryptonote
LOG_PRINT_L1("Transaction with id= "<< id << " used already spent key images");
tvc.m_verifivation_failed = true;
tvc.m_double_spend = true;
tvc.m_no_drop_offense = true;
return false;
}
}
@@ -290,7 +299,7 @@ namespace cryptonote
return false;
m_blockchain.add_txpool_tx(id, blob, meta);
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)(tx_weight ? tx_weight : 1), receive_time), id);
add_tx_to_transient_lists(id, fee / (double)(tx_weight ? tx_weight : 1), receive_time);
lock.commit();
}
catch (const std::exception &e)
@@ -361,7 +370,7 @@ namespace cryptonote
m_blockchain.remove_txpool_tx(id);
m_blockchain.add_txpool_tx(id, blob, meta);
m_txs_by_fee_and_receive_time.emplace(std::pair<double, std::time_t>(fee / (double)(tx_weight ? tx_weight : 1), receive_time), id);
add_tx_to_transient_lists(id, meta.fee / (double)(tx_weight ? tx_weight : 1), receive_time);
}
lock.commit();
}
@@ -382,7 +391,7 @@ namespace cryptonote
++m_cookie;
MINFO("Transaction added to pool: txid " << id << " weight: " << tx_weight << " fee/byte: " << (fee / (double)(tx_weight ? tx_weight : 1)));
MINFO("Transaction added to pool: txid " << id << " weight: " << tx_weight << " fee/byte: " << (fee / (double)(tx_weight ? tx_weight : 1)) << ", count: " << m_added_txs_by_id.size());
prune(m_txpool_max_weight);
@@ -427,8 +436,14 @@ namespace cryptonote
void tx_memory_pool::prune(size_t bytes)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
// Nothing to do if already empty
if (m_txs_by_fee_and_receive_time.empty())
return;
if (bytes == 0)
bytes = m_txpool_max_weight;
CRITICAL_REGION_LOCAL1(m_blockchain);
LockedTXN lock(m_blockchain.get_db());
bool changed = false;
@@ -473,7 +488,13 @@ namespace cryptonote
reduce_txpool_weight(meta.weight);
remove_transaction_keyimages(tx, txid);
MINFO("Pruned tx " << txid << " from txpool: weight: " << meta.weight << ", fee/byte: " << it->first.first);
m_txs_by_fee_and_receive_time.erase(it--);
auto it_prev = it;
--it_prev;
remove_tx_from_transient_lists(it, txid, !meta.matches(relay_category::broadcasted));
it = it_prev;
changed = true;
}
catch (const std::exception &e)
@@ -555,8 +576,7 @@ namespace cryptonote
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
auto sorted_it = find_tx_in_sorted_container(id);
bool sensitive = false;
try
{
LockedTXN lock(m_blockchain.get_db());
@@ -587,6 +607,7 @@ namespace cryptonote
do_not_relay = meta.do_not_relay;
double_spend_seen = meta.double_spend_seen;
pruned = meta.pruned;
sensitive = !meta.matches(relay_category::broadcasted);
// remove first, in case this throws, so key images aren't removed
m_blockchain.remove_txpool_tx(id);
@@ -600,13 +621,12 @@ namespace cryptonote
return false;
}
if (sorted_it != m_txs_by_fee_and_receive_time.end())
m_txs_by_fee_and_receive_time.erase(sorted_it);
remove_tx_from_transient_lists(find_tx_in_sorted_container(id), id, sensitive);
++m_cookie;
return true;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::get_transaction_info(const crypto::hash &txid, tx_details &td) const
bool tx_memory_pool::get_transaction_info(const crypto::hash &txid, tx_details &td, bool include_sensitive_data, bool include_blob) const
{
PERF_TIMER(get_transaction_info);
CRITICAL_REGION_LOCAL(m_transactions_lock);
@@ -618,7 +638,12 @@ namespace cryptonote
txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(txid, meta))
{
MERROR("Failed to find tx in txpool");
LOG_PRINT_L2("Failed to find tx in txpool: " << txid);
return false;
}
if (!include_sensitive_data && !meta.matches(relay_category::broadcasted))
{
// We don't want sensitive data && the tx is sensitive, so no need to return it
return false;
}
cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid, relay_category::all);
@@ -644,11 +669,13 @@ namespace cryptonote
td.kept_by_block = meta.kept_by_block;
td.last_failed_height = meta.last_failed_height;
td.last_failed_id = meta.last_failed_id;
td.receive_time = meta.receive_time;
td.last_relayed_time = meta.dandelionpp_stem ? 0 : meta.last_relayed_time;
td.receive_time = include_sensitive_data ? meta.receive_time : 0;
td.last_relayed_time = (include_sensitive_data && !meta.dandelionpp_stem) ? meta.last_relayed_time : 0;
td.relayed = meta.relayed;
td.do_not_relay = meta.do_not_relay;
td.double_spend_seen = meta.double_spend_seen;
if (include_blob)
td.tx_blob = std::move(txblob);
}
catch (const std::exception &e)
{
@@ -658,6 +685,25 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------
bool tx_memory_pool::get_transactions_info(const std::vector<crypto::hash>& txids, std::vector<std::pair<crypto::hash, tx_details>>& txs, bool include_sensitive) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
txs.clear();
for (const auto &it: txids)
{
tx_details details;
bool success = get_transaction_info(it, details, include_sensitive, true/*include_blob*/);
if (success)
{
txs.push_back(std::make_pair(it, std::move(details)));
}
}
return true;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::get_complement(const std::vector<crypto::hash> &hashes, std::vector<cryptonote::blobdata> &txes) const
{
@@ -719,15 +765,7 @@ namespace cryptonote
(tx_age > CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && meta.kept_by_block) )
{
LOG_PRINT_L1("Tx " << txid << " removed from tx pool due to outdated, age: " << tx_age );
auto sorted_it = find_tx_in_sorted_container(txid);
if (sorted_it == m_txs_by_fee_and_receive_time.end())
{
LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!");
}
else
{
m_txs_by_fee_and_receive_time.erase(sorted_it);
}
remove_tx_from_transient_lists(find_tx_in_sorted_container(txid), txid, !meta.matches(relay_category::broadcasted));
m_timed_out_transactions.insert(txid);
remove.push_back(std::make_pair(txid, meta.weight));
}
@@ -881,9 +919,12 @@ namespace cryptonote
meta.last_relayed_time = std::chrono::system_clock::to_time_t(now);
m_blockchain.update_txpool_tx(hash, meta);
// wait until db update succeeds to ensure tx is visible in the pool
was_just_broadcasted = !already_broadcasted && meta.matches(relay_category::broadcasted);
if (was_just_broadcasted)
// Make sure the tx gets re-added with an updated time
add_tx_to_transient_lists(hash, meta.fee / (double)meta.weight, std::chrono::system_clock::to_time_t(now));
}
}
catch (const std::exception &e)
@@ -936,6 +977,81 @@ namespace cryptonote
}, false, category);
}
//------------------------------------------------------------------
bool tx_memory_pool::get_pool_info(time_t start_time, bool include_sensitive, size_t max_tx_count, std::vector<std::pair<crypto::hash, tx_details>>& added_txs, std::vector<crypto::hash>& remaining_added_txids, std::vector<crypto::hash>& removed_txs, bool& incremental) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
incremental = true;
if (start_time == (time_t)0)
{
// Giving no start time means give back whole pool
incremental = false;
}
else if ((m_added_txs_start_time != (time_t)0) && (m_removed_txs_start_time != (time_t)0))
{
if ((start_time <= m_added_txs_start_time) || (start_time <= m_removed_txs_start_time))
{
// If either of the two lists do not go back far enough it's not possible to
// deliver incremental pool info
incremental = false;
}
// The check uses "<=": We cannot be sure to have ALL txs exactly at start_time, only AFTER that time
}
else
{
// Some incremental info still missing completely
incremental = false;
}
added_txs.clear();
remaining_added_txids.clear();
removed_txs.clear();
std::vector<crypto::hash> txids;
if (!incremental)
{
LOG_PRINT_L2("Giving back the whole pool");
// Give back the whole pool in 'added_txs'; because calling 'get_transaction_info' right inside the
// anonymous method somehow results in an LMDB error with transactions we have to build a list of
// ids first and get the full info afterwards
get_transaction_hashes(txids, include_sensitive);
if (txids.size() > max_tx_count)
{
remaining_added_txids = std::vector<crypto::hash>(txids.begin() + max_tx_count, txids.end());
txids.erase(txids.begin() + max_tx_count, txids.end());
}
get_transactions_info(txids, added_txs, include_sensitive);
return true;
}
// Give back incrementally, based on time of entry into the map
for (const auto &pit : m_added_txs_by_id)
{
if (pit.second >= start_time)
txids.push_back(pit.first);
}
get_transactions_info(txids, added_txs, include_sensitive);
if (added_txs.size() > max_tx_count)
{
remaining_added_txids.reserve(added_txs.size() - max_tx_count);
for (size_t i = max_tx_count; i < added_txs.size(); ++i)
remaining_added_txids.push_back(added_txs[i].first);
added_txs.erase(added_txs.begin() + max_tx_count, added_txs.end());
}
std::multimap<time_t, removed_tx_info>::const_iterator rit = m_removed_txs_by_time.lower_bound(start_time);
while (rit != m_removed_txs_by_time.end())
{
if (include_sensitive || !rit->second.sensitive)
{
removed_txs.push_back(rit->second.txid);
}
++rit;
}
return true;
}
//------------------------------------------------------------------
void tx_memory_pool::get_transaction_backlog(std::vector<tx_backlog_entry>& backlog, bool include_sensitive) const
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
@@ -970,7 +1086,7 @@ namespace cryptonote
// If the total weight is too high, choose the best paying transactions
if (total_weight > max_backlog_weight)
std::sort(tmp.begin(), tmp.end(), [](const auto& a, const auto& b){ return a.fee * b.weight > b.fee * a.weight; });
std::stable_sort(tmp.begin(), tmp.end(), [](const auto& a, const auto& b){ return a.fee * b.weight > b.fee * a.weight; });
backlog.clear();
uint64_t w = 0;
@@ -1489,8 +1605,9 @@ namespace cryptonote
return ss.str();
}
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate
bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version)
bool tx_memory_pool::fill_block_template(block &bl, size_t median_weight, uint64_t already_generated_coins, size_t &total_weight, uint64_t &fee, uint64_t &expected_reward, uint8_t version, oracle::pricing_record& pr, std::map<std::string, uint64_t>& circ_supply, std::vector<txpool_tx_meta_t>& protocol_metadata)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
@@ -1528,6 +1645,7 @@ namespace cryptonote
warned = true;
continue;
}
LOG_PRINT_L2("Considering " << sorted_it->second << ", weight " << meta.weight << ", current block weight " << total_weight << "/" << max_total_weight << ", current coinbase " << print_money(best_coinbase) << ", relay method " << (unsigned)meta.get_relay_method());
if (!meta.matches(relay_category::legacy) && !(m_mine_stem_txes && meta.get_relay_method() == relay_method::stem))
@@ -1599,14 +1717,14 @@ namespace cryptonote
if (memcmp(&original_meta, &meta, sizeof(meta)))
{
try
{
m_blockchain.update_txpool_tx(sorted_it->second, meta);
}
{
m_blockchain.update_txpool_tx(sorted_it->second, meta);
}
catch (const std::exception &e)
{
MERROR("Failed to update tx meta: " << e.what());
// continue, not fatal
}
{
MERROR("Failed to update tx meta: " << e.what());
// continue, not fatal
}
}
if (!ready)
{
@@ -1619,6 +1737,14 @@ namespace cryptonote
continue;
}
// Check what the TX type is - only CONVERT needs a cash_value
if (meta.source_asset_id == meta.destination_asset_id) {
// TRANSFER
} else {
// BURN OR CONVERT (both require inclusion in the protocol_tx calculation for circ_supply purposes)
protocol_metadata.push_back(meta);
}
bl.tx_hashes.push_back(sorted_it->second);
total_weight += meta.weight;
fee += meta.fee;
@@ -1640,6 +1766,12 @@ namespace cryptonote
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
// Simply throw away incremental info, too difficult to update
m_added_txs_by_id.clear();
m_added_txs_start_time = (time_t)0;
m_removed_txs_by_time.clear();
m_removed_txs_start_time = (time_t)0;
MINFO("Validating txpool contents for v" << (unsigned)version);
LockedTXN lock(m_blockchain.get_db());
@@ -1697,6 +1829,106 @@ namespace cryptonote
return n_removed;
}
//---------------------------------------------------------------------------------
void tx_memory_pool::add_tx_to_transient_lists(const crypto::hash& txid, double fee, time_t receive_time)
{
time_t now = time(NULL);
const std::unordered_map<crypto::hash, time_t>::iterator it = m_added_txs_by_id.find(txid);
if (it == m_added_txs_by_id.end())
{
m_added_txs_by_id.insert(std::make_pair(txid, now));
}
else
{
// This tx was already added to the map earlier, probably because then it was in the "stem"
// phase of Dandelion++ and now is in the "fluff" phase i.e. got broadcasted: We have to set
// a new time for clients that are not allowed to see sensitive txs to make sure they will
// see it now if they query incrementally
it->second = now;
auto sorted_it = find_tx_in_sorted_container(txid);
if (sorted_it == m_txs_by_fee_and_receive_time.end())
{
MDEBUG("Re-adding tx " << txid << " to tx pool, but it was not found in the sorted txs container");
}
else
{
m_txs_by_fee_and_receive_time.erase(sorted_it);
}
}
m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(fee, receive_time), txid);
// Don't check for "resurrected" txs in case of reorgs i.e. don't check in 'm_removed_txs_by_time'
// whether we have that txid there and if yes remove it; this results in possible duplicates
// where we return certain txids as deleted AND in the pool at the same time which requires
// clients to process deleted ones BEFORE processing pool txs
if (m_added_txs_start_time == (time_t)0)
{
m_added_txs_start_time = now;
}
}
//---------------------------------------------------------------------------------
void tx_memory_pool::remove_tx_from_transient_lists(const cryptonote::sorted_tx_container::iterator& sorted_it, const crypto::hash& txid, bool sensitive)
{
if (sorted_it == m_txs_by_fee_and_receive_time.end())
{
LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!");
}
else
{
m_txs_by_fee_and_receive_time.erase(sorted_it);
}
const std::unordered_map<crypto::hash, time_t>::iterator it = m_added_txs_by_id.find(txid);
if (it != m_added_txs_by_id.end())
{
m_added_txs_by_id.erase(it);
}
else
{
MDEBUG("Removing tx " << txid << " from tx pool, but it was not found in the map of added txs");
}
track_removed_tx(txid, sensitive);
}
//---------------------------------------------------------------------------------
void tx_memory_pool::track_removed_tx(const crypto::hash& txid, bool sensitive)
{
time_t now = time(NULL);
m_removed_txs_by_time.insert(std::make_pair(now, removed_tx_info{txid, sensitive}));
MDEBUG("Transaction removed from pool: txid " << txid << ", total entries in removed list now " << m_removed_txs_by_time.size());
if (m_removed_txs_start_time == (time_t)0)
{
m_removed_txs_start_time = now;
}
// Simple system to make sure the list of removed ids does not swell to an unmanageable size: Set
// an absolute size limit plus delete entries that are x minutes old (which is ok because clients
// will sync with sensible time intervalls and should not ask for incremental info e.g. 1 hour back)
const int MAX_REMOVED = 20000;
if (m_removed_txs_by_time.size() > MAX_REMOVED)
{
auto erase_it = m_removed_txs_by_time.begin();
std::advance(erase_it, MAX_REMOVED / 4 + 1);
m_removed_txs_by_time.erase(m_removed_txs_by_time.begin(), erase_it);
m_removed_txs_start_time = m_removed_txs_by_time.begin()->first;
MDEBUG("Erased old transactions from big removed list, leaving " << m_removed_txs_by_time.size());
}
else
{
time_t earliest = now - (30 * 60); // 30 minutes
std::map<time_t, removed_tx_info>::iterator from, to;
from = m_removed_txs_by_time.begin();
to = m_removed_txs_by_time.lower_bound(earliest);
int distance = std::distance(from, to);
if (distance > 0)
{
m_removed_txs_by_time.erase(from, to);
m_removed_txs_start_time = earliest;
MDEBUG("Erased " << distance << " old transactions from removed list, leaving " << m_removed_txs_by_time.size());
}
}
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::init(size_t max_txpool_weight, bool mine_stem_txes)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
@@ -1704,6 +1936,10 @@ namespace cryptonote
m_txpool_max_weight = max_txpool_weight ? max_txpool_weight : DEFAULT_TXPOOL_MAX_WEIGHT;
m_txs_by_fee_and_receive_time.clear();
m_added_txs_by_id.clear();
m_added_txs_start_time = (time_t)0;
m_removed_txs_by_time.clear();
m_removed_txs_start_time = (time_t)0;
m_spent_key_images.clear();
m_txpool_weight = 0;
std::vector<crypto::hash> remove;
@@ -1728,7 +1964,7 @@ namespace cryptonote
MFATAL("Failed to insert key images from txpool tx");
return false;
}
m_txs_by_fee_and_receive_time.emplace(std::pair<double, time_t>(meta.fee / (double)meta.weight, meta.receive_time), txid);
add_tx_to_transient_lists(txid, meta.fee / (double)meta.weight, meta.receive_time);
m_txpool_weight += meta.weight;
return true;
}, true, relay_category::all);

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