Compare commits

...

117 Commits

Author SHA1 Message Date
Some Random Crypto Guy 9d9471d314 fixed a couple of unit_test issues; bumped RC version 2025-04-01 12:18:56 +01:00
Some Random Crypto Guy 5da798a7c5 Merge remote-tracking branch 'origin/fix-all-unit-tests' into develop 2025-03-31 11:31:49 +01:00
akildemir 0f97ec9ea7 fix unit-tests 2025-03-31 10:49:39 +03:00
Some Random Crypto Guy 0418bfee30 fixed asio-related tests 2025-03-27 11:08:33 +00:00
Some Random Crypto Guy 488d5f1e9b updated fast sync checkpoints 2025-03-19 11:09:50 +00:00
Some Random Crypto Guy 771b8ea606 Merge branch 'rebase-v0.18' into develop 2025-03-19 09:43:51 +00:00
Some Random Crypto Guy 28262a30fe added unit tests for protocol_tx and check_output_types; bumped version to v0.9.6-rc1 2025-03-19 09:30:02 +00:00
Some Random Crypto Guy aa4276c39e Merge branch 'develop' of https://github.com/salvium/salvium into develop 2025-03-18 12:21:15 +00:00
Some Random Crypto Guy 1f49c178ee fixed build on Linux after background-sync patch applied and broke it! 2025-03-17 11:43:49 +00:00
j-berman f087b3807b wallet: background sync with just the view key
- When background syncing, the wallet wipes the spend key
from memory and processes all new transactions. The wallet saves
all receives, spends, and "plausible" spends of receives the
wallet does not know key images for.
- When background sync disabled, the wallet processes all
background synced txs and then clears the background sync cache.
- Adding "plausible" spends to the background sync cache ensures
that the wallet does not need to query the daemon to see if any
received outputs were spent while background sync was enabled.
This would harm privacy especially for users of 3rd party daemons.
- To enable the feature in the CLI wallet, the user can set
background-sync to reuse-wallet-password or
custom-background-password and the wallet automatically syncs in
the background when the wallet locks, then processes all
background synced txs when the wallet is unlocked.
- The custom-background-password option enables the user to
open a distinct background wallet that only has a view key saved
and can be opened/closed/synced separately from the main wallet.
When the main wallet opens, it processes the background wallet's
cache.
- To enable the feature in the RPC wallet, there is a new
`/setup_background_sync` endpoint.
- HW, multsig and view-only wallets cannot background sync.
2025-03-17 11:27:36 +00:00
Some Random Crypto Guy cb6cdac603 fixed sorting of yield_info output in CLI 2025-03-17 11:22:21 +00:00
akildemir 082976a3f0 Merge pull request #15 from salvium/fix-build
merge pr https://github.com/monero-project/monero/pull/9462
2025-03-17 10:40:18 +03:00
Some Random Crypto Guy 420824005e updates to allow building of all platforms using 'make depends' 2025-03-14 05:24:56 +00:00
Some Random Crypto Guy 98ded9b9c4 interim checkin of the rebased code (added files) 2025-03-13 17:58:18 +00:00
Some Random Crypto Guy 9baeb750ac interim checkin of the rebased code 2025-03-13 17:57:28 +00:00
akildemir 1cf81058b6 merge pr https://github.com/monero-project/monero/pull/9462 2025-03-12 15:34:51 +03:00
Some Random Crypto Guy 9570c7a910 Merge branch 'hotfix-v0.9.5a' 2025-03-02 22:26:32 +00:00
Some Random Crypto Guy 23756691b7 Hotfix release to address 2 wallet issues:
1. new wallet "set" parameter "send-change-back-to-subaddress [1|0]"
   The change for a transaction can now be sent back to the main address for the wallet (default)
   or to the sending subaddress
   (* please note that for AUDIT TX type, it will ALWAYS be sent back to the subaddress)

2. fixed erroneous code setting "source_asset" in wallet2::process_new_transaction()
   This bug caused change entries to appear in all TXs when querying using "get_transfer_by_txid"
   RPC method as "in" output types. Whilst this is fully conformant to the Monero Docs that
   describe the method in question, it did not conform to the experience of the RPC method users
   or to traditional Monero RPC output.
2025-03-02 22:15:50 +00:00
Some Random Crypto Guy d5f6cdc0cd tweaked build of audit tool; added asset_type to destinations in RPC get_* calls 2025-02-28 11:51:35 +00:00
Some Random Crypto Guy 378ec75a6e Merge branch 'main' into develop 2025-02-26 13:16:27 +00:00
Some Random Crypto Guy 3eb986fc51 fixed debug build without audit tool 2025-02-25 15:54:50 +00:00
Some Random Crypto Guy b713a08a81 bumped version, ready for fork; fixed up wallet API method for auditing 2025-02-25 13:04:29 +00:00
Some Random Crypto Guy 5bd079af4a updated HF9 block height 2025-02-24 11:50:08 +00:00
Some Random Crypto Guy cd2c7c939c added audit2 as phase 3 2025-02-24 10:57:18 +00:00
Some Random Crypto Guy 2f707e30c6 bumped version number in preparation for hardforks 2025-02-24 10:53:32 +00:00
Some Random Crypto Guy f9726354b8 Merge branch 'develop' 2025-02-24 10:52:28 +00:00
Some Random Crypto Guy fcd78eea7e merged SAL1 support into the wallet API functions 2025-02-24 10:40:13 +00:00
akildemir db740fa037 make a separate tx per subaddress 2025-02-24 13:30:31 +03:00
Some Random Crypto Guy 5971f39e7a added 2nd phase of audit; bumped version 2025-02-19 17:49:38 +00:00
akildemir 02f2eb5ee9 add SAL1 support to wallet api 2025-02-18 12:05:12 +03:00
Some Random Crypto Guy 02ef77bbcc Merge branch 'main' into develop 2025-02-17 23:48:42 +00:00
Some Random Crypto Guy aa64124c28 fix for supply_info command with SAL supply going negative 2025-02-14 13:28:22 +00:00
Some Random Crypto Guy bc7db51f03 various fixes ready for next HF 2025-02-11 14:35:57 +00:00
Some Random Crypto Guy 6889321361 fixed possible throw() when dust in index=0; bumped version number 2025-02-11 12:18:08 +00:00
Some Random Crypto Guy 3cb473132e Merge branch 'main' of https://github.com/salvium/salvium 2025-02-10 13:21:47 +00:00
akildemir b298f542a6 add audit tx support for wallet api (#14) 2025-02-10 13:20:42 +00:00
Some Random Crypto Guy eb9f799b8b fixed syncing message error level; added thread library for auditing 2025-02-10 13:11:52 +00:00
Some Random Crypto Guy 8bf35db67e fixed submodules that got merged incorrectly 2025-02-04 10:40:49 +00:00
Some Random Crypto Guy aeef1a6677 Merge branch 'main' of https://github.com/somerandomcryptoguy/salvium-private 2025-02-04 10:16:10 +00:00
Some Random Crypto Guy ee586a3fca added asset_type check - sorry, sneaky hackers, but you have a spy in your midst ;) 2025-02-04 10:09:49 +00:00
Some Random Crypto Guy 19be3a6146 fixed gitignore issue with CMake and audit tool 2025-01-31 17:20:52 +00:00
Some Random Crypto Guy 64a69268fe set hard fork 6 height; bumped version number 2025-01-31 15:10:13 +00:00
Some Random Crypto Guy 7312652540 Merge branch 'develop' 2025-01-31 15:07:59 +00:00
Some Random Crypto Guy 8cd587ec54 added building of (private) audit tool; improved help text for AUDIT command in CLI 2025-01-30 13:56:17 +00:00
Some Random Crypto Guy 62c43a4ed2 added audit index=all command; added audit RPC command; bumped version 2025-01-30 12:59:33 +00:00
Some Random Crypto Guy 0180051a8c fixed #23 : If multiple inputs get sent on a single transaction, then return_payment will not return all those inputs
fixed #20 : Audit transaction is showing in yield_info, but says 0 yield
fixed #19 : if you send SAL1, while the tx is pending it shows in the sal balance
fixed #18 : yield_info display is showing the wrong unlock time (TESTNET)
fixed #17 : SAL appears to be accrued during audit
2025-01-29 22:32:41 +00:00
Some Random Crypto Guy a7c1ba652b interim checkin of changes for audit; bumped version number 2025-01-29 15:39:08 +00:00
Some Random Crypto Guy 2a4d08b67f Merge branch 'main' into develop 2025-01-29 12:38:05 +00:00
Some Random Crypto Guy 3fc5ea3543 set fork height; updated fast-sync checkpoints 2025-01-08 18:44:12 +00:00
Some Random Crypto Guy 3b72dc0555 added code to skip user TXs in v5 when filling block template 2025-01-07 23:23:44 +00:00
Some Random Crypto Guy b48c86afe0 added user tx verification 2025-01-07 22:53:58 +00:00
Some Random Crypto Guy 0f88d91fa0 bumped version 2025-01-07 16:57:19 +00:00
Some Random Crypto Guy f4612357b2 Merge branch 'protocol-tx-rewrite' 2025-01-02 12:46:26 +00:00
Some Random Crypto Guy e9a2b6fbb7 additional checks needed for protocol_tx validation 2024-12-27 15:36:41 +00:00
akildemir ca2069facc rewrite protocol tx construct/validate 2024-12-27 11:51:33 +03:00
Some Random Crypto Guy 114297d784 fixed switch values in validation; bumped version 2024-12-20 09:48:00 +00:00
Some Random Crypto Guy 6368aee05f bumped version for consensus rules hard fork 2024-12-19 11:31:05 +00:00
Some Random Crypto Guy 8599cdf95b Merge branch 'main' of https://github.com/salvium/salvium 2024-12-18 12:14:53 +00:00
Some Random Crypto Guy d39f2f180e set fork height 2024-12-18 12:04:32 +00:00
Some Random Crypto Guy c763febe98 bumped mainline version to v0.7.0 2024-12-18 12:04:32 +00:00
Some Random Crypto Guy cef01372b1 updated block fast sync checksums; disabled spend authority proof due to multisig; fixed issue with duplicate keys; bumped version 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy e15dbb5db2 added belt and braces to prevent CONVERT TXs from being attempted; integrated spend authority proof support into wallet; bumped version number 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 82d706aacb bumped RC version 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy f3522764a1 switched to single spend authority proof - the dummy proofs don't work as intended, so dropping them 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 0448a6bf9a interim checkin 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 2ce22c2508 partial working serialisation 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 1334bac45a fixed check on miner-staker split 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy e909e3eef1 fixed unit tests; fixed core tests; fixed performance tests; added fix to prevent change in block reward split (thanks Akil); added prelim code for spend authority proof - not complete / working 2024-12-18 12:04:02 +00:00
Some Random Crypto Guy 4b594142ca updated block fast sync checksums; disabled spend authority proof due to multisig; fixed issue in protocol_tx; bumped version 2024-12-17 20:06:54 +00:00
Some Random Crypto Guy 29e435bd39 added belt and braces to prevent CONVERT TXs from being attempted; integrated spend authority proof support into wallet; bumped version number 2024-12-16 14:07:37 +00:00
Some Random Crypto Guy 4abde92c1a bumped RC version 2024-12-16 09:18:47 +00:00
Some Random Crypto Guy dd23331df9 switched to single spend authority proof - the dummy proofs don't work as intended, so dropping them 2024-12-16 09:16:34 +00:00
Some Random Crypto Guy 7d2025bc19 interim checkin 2024-12-16 07:48:16 +00:00
Some Random Crypto Guy a01422a5e0 partial working serialisation 2024-12-15 22:28:14 +00:00
Some Random Crypto Guy e68f7f46ed fixed check on miner-staker split 2024-12-15 11:50:14 +00:00
Some Random Crypto Guy b87c243da1 fixed unit tests; fixed core tests; fixed performance tests; added fix to prevent change in block reward split (thanks Akil); added prelim code for spend authority proof - not complete / working 2024-12-15 11:09:46 +00:00
Some Random Crypto Guy 49fd907073 Merge branch 'main' into develop 2024-12-12 21:08:33 +00:00
SomeRandomDevopsGuy 8c999520d1 add RPC (#11)
Co-authored-by: srdg <srdg@srdg.io>
2024-11-18 18:39:04 +00:00
Some Random Crypto Guy 945bdc72e7 Merge branch 'hotfix-0.6.4' 2024-11-16 00:49:08 +00:00
Some Random Crypto Guy c6d843b6f5 hotfix to address the 'difficulty overhead' chain issues; added more fasta-sync checkpoints; bumped version number 2024-11-16 00:48:31 +00:00
Some Random Crypto Guy 8f5111aeda Merge branch 'main' into develop 2024-11-05 12:39:42 +00:00
Some Random Crypto Guy b285ec550d fixed edge case where returning pre-HF2 transfer using HF2 CLI wallet _before_ HF2; bumped version 2024-10-31 18:37:41 +00:00
Some Random Crypto Guy afc2518ef7 fixed boundary condition returning pre-HF2 TXs; removed a couple of extraneous vars; added a logging message; bumped version 2024-10-31 11:47:20 +00:00
Some Random Crypto Guy a9406b158d fixed full reward zone buffer on fork transition to match between daemon and wallet 2024-10-30 15:48:45 +00:00
Some Random Crypto Guy e45643e157 increased max TX size from HF2; bumped version number 2024-10-30 14:31:27 +00:00
Some Random Crypto Guy 1df18ca6a4 added hard fork 2 for v0.6.0 2024-10-22 12:04:03 +01:00
Some Random Crypto Guy 91b2ec275a Updated + fixed translations mechanism; updated fast-sync checkpoints; bumped version 2024-10-22 12:03:29 +01:00
Some Random Crypto Guy e45fdb863c Merge branch 'develop' 2024-10-21 14:18:51 +01:00
Some Random Crypto Guy cb2f9d3f75 updated seed IPs, updated mainnet checksums, bumped version 2024-10-18 14:37:36 +01:00
Some Random Crypto Guy 59025bb27b updated fast-sync checkpoints; updated testnet seed IPs 2024-10-18 13:55:50 +01:00
Some Random Crypto Guy 204c6fc778 fixed issue with migration to new difficulty algorithm; bumped version 2024-10-18 12:37:59 +01:00
Some Random Crypto Guy 78c2b4b1fb import of blockchain scanner - unfinished 2024-10-16 17:55:46 +01:00
Some Random Crypto Guy fcac456902 import of blockchain scanner - unfinished 2024-10-16 17:54:45 +01:00
Some Random Crypto Guy 1824a34a68 bumped version, ready for testnet 2024-10-15 12:08:58 +01:00
Some Random Crypto Guy 1786c628bf disabled yield reporting until daemon is synced 2024-10-15 11:26:14 +01:00
Some Random Crypto Guy 6b8df3cee5 disabled STAKE for multisig - deferred solution until Salvium One 2024-10-15 11:25:42 +01:00
Some Random Crypto Guy 884db2b499 solved issue of STAKE TXs paying out without view_tags; bumped version 2024-10-14 10:55:57 +01:00
Some Random Crypto Guy ce7a1bdd96 working multisig N-out-TX support 2024-10-11 13:38:07 +01:00
Some Random Crypto Guy 57cbb146db working multisig N-out-TX support 2024-10-11 13:29:55 +01:00
Some Random Crypto Guy 85c856411e resolved indexing error with m_transfers_indices changing from vector to set 2024-10-09 13:41:01 +01:00
Some Random Crypto Guy 6fefb49da0 fixed merge regression in wallet; updated build order for binary releases 2024-10-09 13:37:14 +01:00
Some Random Crypto Guy c5c828516b merged N-out-TX and multisig support; implemented new difficulty algorithm; bumped version 2024-10-09 13:20:51 +01:00
Some Random Crypto Guy 218911d9fc bumped RC version 2024-10-09 12:24:29 +01:00
Some Random Crypto Guy da3ef2511d fixed return_payment issues for N-out-TXs; fixed change_index being incorrect datatype; partial fix to asset_type RPC propagation issue 2024-10-09 12:21:50 +01:00
Some Random Crypto Guy 8b2b039036 N-out-TX support working for simple cases - needs edge case testing still 2024-10-08 12:03:20 +01:00
Some Random Crypto Guy 4d1c84fcaf Merge branch 'develop' 2024-10-04 10:06:24 +01:00
Some Random Crypto Guy bb91b01cf7 Merge branch 'multisig' into develop 2024-10-03 13:48:42 +01:00
Some Random Crypto Guy 7f0eda828a disabled staking on multisig wallets 2024-10-03 13:20:25 +01:00
Some Random Crypto Guy d3f15211d7 updated to support multisig wallets; fixed a couple of minor bugs; removed some extraneous code; bumped version 2024-10-03 10:01:29 +01:00
Some Random Crypto Guy b828703bbd added maturation block to output of yield_info in CLI wallet 2024-09-30 14:38:41 +01:00
Some Random Crypto Guy 2fa8ef97ef started work on support for STAKE and BURN commands in multisig 2024-09-30 13:08:07 +01:00
Some Random Crypto Guy acb3af43f0 initial implementation of multisig wallet / TX support 2024-09-27 16:15:42 +01:00
Some Random Crypto Guy d1eed6e9ff interim commit - NOT TESTED 2024-09-14 11:06:23 +01:00
Some Random Crypto Guy 30a2931067 fixed copy/paste glitch on previous 2024-09-09 12:01:15 +01:00
Some Random Crypto Guy 1c73dd0c9f switch to LWMA difficulty algorithm for HF2+ 2024-09-08 19:54:12 +01:00
Some Random Crypto Guy 1c84c00fe6 Merge branch 'main' into develop, ahead of new Salvium One development 2024-09-02 15:26:40 +01:00
SomeRandomDevopsGuy 7abf28d87c feat: Cross-Platform Binary Build and S3 Upload GitHub Action (#5)
* add CI

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

* add deploy

---------

Co-authored-by: SomeRandomDevopsGuy <srdg@srdg.io>
2024-09-02 12:08:32 +01:00
220 changed files with 37036 additions and 31022 deletions
+127
View File
@@ -0,0 +1,127 @@
name: ci/gh-actions/depends
on:
push:
paths-ignore:
- 'docs/**'
- '**/README.md'
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
USE_DEVICE_TREZOR_MANDATORY: ON
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-darwin"
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-darwin"
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: "ARMv8 Android"
# host: "aarch64-linux-android"
# packages: "gperf cmake python3"
name: ${{ matrix.toolchain.name }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
submodules: recursive
# Most volatile cache
- name: ccache
uses: actions/cache@v4
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@v4
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@v4
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 libssl-dev 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@v4
if: ${{ matrix.toolchain.host == 'x86_64-w64-mingw32' || matrix.toolchain.host == 'x86_64-apple-darwin' || matrix.toolchain.host == 'aarch64-apple-darwin' || matrix.toolchain.host == 'x86_64-unknown-linux-gnu' }}
with:
name: ${{ matrix.toolchain.name }}
path: |
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-*
/home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salviumd*
- name: zip daemon & cli
run: |
zip salvium-${GITHUB_REF_NAME}-${{ matrix.toolchain.host }}.zip /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-rpc* /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salvium-wallet-cli* /home/runner/work/${{ github.event.repository.name }}/${{ github.event.repository.name }}/build/${{ matrix.toolchain.host }}/release/bin/salviumd*
ls -l
- name: "Deploy"
uses: keithweaver/aws-s3-github-action@v1.0.0
with:
command: cp
source: ./salvium-${{ github.ref_name }}-${{ matrix.toolchain.host }}.zip
destination: s3://${{ vars.S3_BUCKET }}/salvium-${{ github.ref_name }}-${{ matrix.toolchain.host }}.zip
aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws_secret_access_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws_region: eu-west-1
flags: --acl public-read
+3
View File
@@ -30,6 +30,9 @@ contrib/gitian/builder/
contrib/gitian/docker/
contrib/gitian/sigs/
# Audit tool
src/blockchain_utilities/blockchain_audit.cpp
# Created by https://www.gitignore.io
### C++ ###
+3
View File
@@ -14,3 +14,6 @@
[submodule "external/miniupnp"]
path = external/miniupnp
url = https://github.com/miniupnp/miniupnp
[submodule "external/mx25519"]
path = external/mx25519
url = https://github.com/tevador/mx25519
+18 -7
View File
@@ -531,14 +531,14 @@ add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}")
# Can't install hook in static build on OSX, because OSX linker does not support --wrap
# On ARM, having libunwind package (with .so's only) installed breaks static link.
# When possible, avoid stack tracing using libunwind in favor of using easylogging++.
if (APPLE OR NETBSD)
if (APPLE)
set(DEFAULT_STACK_TRACE OFF)
set(LIBUNWIND_LIBRARIES "")
elseif (DEPENDS AND NOT LINUX)
set(DEFAULT_STACK_TRACE OFF)
set(LIBUNWIND_LIBRARIES "")
elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW)
set(DEFAULT_STACK_TRACE OFF)
set(DEFAULT_STACK_TRACE ON)
set(STACK_TRACE_LIB "easylogging++") # for diag output only
set(LIBUNWIND_LIBRARIES "")
elseif (ARM)
@@ -547,7 +547,7 @@ elseif (ARM)
else()
find_package(Libunwind)
if(LIBUNWIND_FOUND)
set(DEFAULT_STACK_TRACE OFF)
set(DEFAULT_STACK_TRACE ON)
set(STACK_TRACE_LIB "libunwind") # for diag output only
else()
set(DEFAULT_STACK_TRACE OFF)
@@ -1084,6 +1084,7 @@ endif()
find_package(Boost 1.58 QUIET REQUIRED COMPONENTS ${BOOST_COMPONENTS})
add_definitions(-DBOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION)
add_definitions(-DBOOST_NO_AUTO_PTR)
add_definitions(-DBOOST_UUID_DISABLE_ALIGNMENT) # This restores UUID's std::has_unique_object_representations property
set(CMAKE_FIND_LIBRARY_SUFFIXES ${OLD_LIB_SUFFIXES})
if(NOT Boost_FOUND)
@@ -1107,7 +1108,9 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
if(MINGW)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj")
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt)
if(NOT DEPENDS)
if(DEPENDS)
set(ICU_LIBRARIES icuio icui18n icuuc icudata icutu iconv)
else()
set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv)
endif()
elseif(APPLE OR OPENBSD OR ANDROID)
@@ -1182,7 +1185,6 @@ endif()
if(STATIC)
set(sodium_USE_STATIC_LIBS ON)
endif()
find_package(Sodium REQUIRED)
find_path(ZMQ_INCLUDE_PATH zmq.h)
find_library(ZMQ_LIB zmq)
@@ -1190,6 +1192,7 @@ find_library(PGM_LIBRARY pgm)
find_library(NORM_LIBRARY norm)
find_library(GSSAPI_LIBRARY gssapi_krb5)
find_library(PROTOLIB_LIBRARY protolib)
find_library(SODIUM_LIBRARY sodium)
find_library(BSD_LIBRARY bsd)
find_library(MD_LIBRARY md)
find_library(PROTOKIT_LIBRARY protokit)
@@ -1212,8 +1215,16 @@ endif()
if(PROTOLIB_LIBRARY)
set(ZMQ_LIB "${ZMQ_LIB};${PROTOLIB_LIBRARY}")
endif()
if(Sodium_FOUND)
set(ZMQ_LIB "${ZMQ_LIB};${sodium_LIBRARIES}")
if(SODIUM_LIBRARY)
message(STATUS "ZMQ_LIB: ${ZMQ_LIB};${SODIUM_LIBRARY}")
set(ZMQ_LIB "${ZMQ_LIB};${SODIUM_LIBRARY}")
find_path(SODIUM_INCLUDE_PATH sodium/crypto_verify_32.h)
if (SODIUM_INCLUDE_PATH)
message(STATUS "SODIUM_INCLUDE_PATH: ${SODIUM_INCLUDE_PATH}")
include_directories(${SODIUM_INCLUDE_PATH})
else()
message(FATAL_ERROR "Could not find required sodium/crypto_verify_32.h")
endif()
endif()
if(BSD_LIBRARY)
set(ZMQ_LIB "${ZMQ_LIB};${BSD_LIBRARY}")
+5 -5
View File
@@ -1,4 +1,4 @@
# Salvium Zero v0.4.1
# Salvium Zero v0.9.6
Copyright (c) 2023-2024, Salvium
Portions Copyright (c) 2014-2023, The Monero Project
@@ -172,7 +172,7 @@ invokes cmake commands as needed.
```bash
cd salvium
git checkout release-v0.18
git checkout v0.9.6
make
```
@@ -251,7 +251,7 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
```bash
git clone https://github.com/salvium/salvium
cd salvium
git checkout v0.4.1
git checkout v0.9.6
```
* Build:
@@ -370,10 +370,10 @@ application.
cd salvium
```
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.4.1'. If you don't care about the version and just want binaries from master, skip this step:
* If you would like a specific [version/tag](https://github.com/salvium/salvium/tags), do a git checkout for that version. eg. 'v0.9.6'. If you don't care about the version and just want binaries from master, skip this step:
```bash
git checkout v0.4.1
git checkout v0.9.6
```
* If you are on a 64-bit system, run:
+66
View File
@@ -0,0 +1,66 @@
depends_prefix="`dirname ${ac_site_file}`/.."
cross_compiling=maybe
host_alias=@HOST@
ac_tool_prefix=${host_alias}-
if test -z $with_boost; then
with_boost=$depends_prefix
fi
if test x@host_os@ = xdarwin; then
BREW=no
PORT=no
fi
PATH=$depends_prefix/native/bin:$PATH
PKG_CONFIG="`which pkg-config` --static"
# These two need to remain exported because pkg-config does not see them
# otherwise. That means they must be unexported at the end of configure.ac to
# avoid ruining the cache. Sigh.
export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig
if test -z "@allow_host_packages@"; then
export PKGCONFIG_LIBDIR=
fi
CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS"
LDFLAGS="-L$depends_prefix/lib $LDFLAGS"
CC="@CC@"
CXX="@CXX@"
OBJC="${CC}"
CCACHE=$depends_prefix/native/bin/ccache
PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH
if test -n "@AR@"; then
AR=@AR@
ac_cv_path_ac_pt_AR=${AR}
fi
if test -n "@RANLIB@"; then
RANLIB=@RANLIB@
ac_cv_path_ac_pt_RANLIB=${RANLIB}
fi
if test -n "@NM@"; then
NM=@NM@
ac_cv_path_ac_pt_NM=${NM}
fi
if test -n "@debug@"; then
enable_reduce_exports=no
fi
if test -n "@CFLAGS@"; then
CFLAGS="@CFLAGS@ $CFLAGS"
fi
if test -n "@CXXFLAGS@"; then
CXXFLAGS="@CXXFLAGS@ $CXXFLAGS"
fi
if test -n "@CPPFLAGS@"; then
CPPFLAGS="@CPPFLAGS@ $CPPFLAGS"
fi
if test -n "@LDFLAGS@"; then
LDFLAGS="@LDFLAGS@ $LDFLAGS"
fi
+8 -8
View File
@@ -1,8 +1,9 @@
package=boost
$(package)_version=1_64_0
$(package)_download_path=https://downloads.sourceforge.net/project/boost/boost/1.64.0/
$(package)_file_name=$(package)_$($(package)_version).tar.bz2
$(package)_sha256_hash=7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332
$(package)_version=1.66.0
$(package)_download_path=https://archives.boost.io/release/$($(package)_version)/source/
$(package)_file_name=$(package)_$(subst .,_,$($(package)_version)).tar.gz
$(package)_sha256_hash=bd0df411efd9a585e5a2212275f8762079fed8842264954675a4fddc46cfcf60
$(package)_dependencies=libiconv
$(package)_patches=fix_aroptions.patch fix_arm_arch.patch
define $(package)_set_vars
@@ -21,11 +22,10 @@ $(package)_toolset_$(host_os)=gcc
$(package)_archiver_$(host_os)=$($(package)_ar)
$(package)_toolset_darwin=darwin
$(package)_archiver_darwin=$($(package)_libtool)
$(package)_config_libraries_$(host_os)="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization"
$(package)_config_libraries_mingw32="chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale"
$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale
$(package)_cxxflags=-std=c++11
$(package)_cxxflags_linux=-fPIC
$(package)_cxxflags_freebsd=-fPIC
$(package)_cxxflags_freebsd=-fPIC -DBOOST_ASIO_HAS_STD_STRING_VIEW=1
endef
define $(package)_preprocess_cmds
@@ -35,7 +35,7 @@ define $(package)_preprocess_cmds
endef
define $(package)_config_cmds
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries_$(host_os))
./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries)
endef
define $(package)_build_cmds
+27
View File
@@ -0,0 +1,27 @@
package=icu4c
$(package)_version=55.2
$(package)_download_path=https://github.com/unicode-org/icu/releases/download/release-55-2/
$(package)_file_name=$(package)-55_2-src.tgz
$(package)_sha256_hash=eda2aa9f9c787748a2e2d310590720ca8bcc6252adf6b4cfb03b65bef9d66759
$(package)_patches=icu-001-dont-build-static-dynamic-twice.patch
define $(package)_set_vars
$(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC -DENABLE_STATIC=YES -DPGKDATA_MODE=static"
endef
define $(package)_config_cmds
patch -p1 < $($(package)_patch_dir)/icu-001-dont-build-static-dynamic-twice.patch &&\
mkdir builda &&\
mkdir buildb &&\
cd builda &&\
sh ../source/runConfigureICU Linux &&\
make &&\
cd ../buildb &&\
sh ../source/runConfigureICU MinGW --enable-static=yes --disable-shared --disable-layout --disable-layoutex --disable-tests --disable-samples --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\
$(MAKE) $($(package)_build_opts)
endef
define $(package)_stage_cmds
cd buildb &&\
$(MAKE) $($(package)_build_opts) DESTDIR=$($(package)_staging_dir) install lib/*
endef
+35
View File
@@ -0,0 +1,35 @@
package=libiconv
$(package)_version=1.15
$(package)_download_path=https://ftp.gnu.org/gnu/libiconv
$(package)_file_name=libiconv-$($(package)_version).tar.gz
$(package)_sha256_hash=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178
$(package)_patches=fix-whitespace.patch
define $(package)_set_vars
$(package)_config_opts=--disable-nls
$(package)_config_opts=--enable-static
$(package)_config_opts=--disable-shared
$(package)_config_opts_linux=--with-pic
$(package)_config_opts_freebsd=--with-pic
endef
define $(package)_preprocess_cmds
cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux/ &&\
patch -p1 < $($(package)_patch_dir)/fix-whitespace.patch
endef
define $(package)_config_cmds
$($(package)_autoconf) AR_FLAGS=$($(package)_arflags)
endef
define $(package)_build_cmds
$(MAKE)
endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
define $(package)_postprocess_cmds
rm lib/*.la
endef
+25
View File
@@ -0,0 +1,25 @@
package=native_ccache
$(package)_version=3.3.4
$(package)_download_path=https://samba.org/ftp/ccache
$(package)_file_name=ccache-$($(package)_version).tar.bz2
$(package)_sha256_hash=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567
define $(package)_set_vars
$(package)_config_opts=
endef
define $(package)_config_cmds
$($(package)_autoconf)
endef
define $(package)_build_cmds
$(MAKE)
endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
define $(package)_postprocess_cmds
rm -rf lib include
endef
+18 -8
View File
@@ -1,28 +1,38 @@
packages:=boost openssl zeromq expat unbound sodium
packages:=boost openssl zeromq libiconv expat unbound
# ccache is useless in gitian builds
ifneq ($(GITIAN),1)
native_packages := native_ccache
endif
hardware_packages := hidapi protobuf libusb
hardware_native_packages := native_protobuf
android_native_packages = android_ndk $(hardware_native_packages)
android_packages = ncurses readline protobuf
android_native_packages = android_ndk
android_packages = ncurses readline sodium
darwin_native_packages = $(hardware_native_packages)
darwin_packages = ncurses readline $(hardware_packages)
darwin_packages = ncurses readline sodium $(hardware_packages)
# not really native...
freebsd_native_packages = freebsd_base $(hardware_native_packages)
freebsd_packages = ncurses readline protobuf libusb
freebsd_native_packages = freebsd_base
freebsd_packages = ncurses readline sodium
linux_packages = eudev ncurses readline $(hardware_packages)
linux_packages = eudev ncurses readline sodium $(hardware_packages)
linux_native_packages = $(hardware_native_packages)
ifeq ($(build_tests),ON)
packages += gtest
endif
mingw32_packages = $(hardware_packages)
ifneq ($(host_arch),riscv64)
linux_packages += unwind
endif
mingw32_packages = icu4c sodium $(hardware_packages)
mingw32_native_packages = $(hardware_native_packages)
ifneq ($(build_os),darwin)
darwin_native_packages += darwin_sdk native_clang native_cctools native_libtapi
endif
+29
View File
@@ -0,0 +1,29 @@
package=unwind
$(package)_version=1.5.0
$(package)_download_path=https://download.savannah.nongnu.org/releases/libunwind
$(package)_file_name=lib$(package)-$($(package)_version).tar.gz
$(package)_sha256_hash=90337653d92d4a13de590781371c604f9031cdb50520366aa1e3a91e1efb1017
$(package)_patches=fix_obj_order.patch
define $(package)_preprocess_cmds
patch -p0 < $($(package)_patch_dir)/fix_obj_order.patch
endef
define $(package)_config_cmds
cp -f $(BASEDIR)/config.guess config/config.guess &&\
cp -f $(BASEDIR)/config.sub config/config.sub &&\
$($(package)_autoconf) --disable-shared --enable-static --disable-tests --disable-documentation AR_FLAGS=$($(package)_arflags)
endef
define $(package)_build_cmds
$(MAKE)
endef
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install
endef
define $(package)_postprocess_cmds
rm lib/*.la
endef
@@ -0,0 +1,37 @@
Don't build object files twice
When passed --enable-static and --enable-shared, icu will generate
both a shared and a static version of its libraries.
However, in order to do so, it builds each and every object file
twice: once with -fPIC (for the shared library), and once without
-fPIC (for the static library). While admittedly building -fPIC for a
static library generates a slightly suboptimal code, this is what all
the autotools-based project are doing. They build each object file
once, and they use it for both the static and shared libraries.
icu builds the object files for the shared library as .o files, and
the object files for static library as .ao files. By simply changing
the suffix of object files used for static libraries to ".o", we tell
icu to use the ones built for the shared library (i.e, with -fPIC),
and avoid the double build of icu.
On a fast build server, this brings the target icu build from
3m41.302s down to 1m43.926s (approximate numbers: some other builds
are running on the system at the same time).
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Index: b/source/config/mh-linux
===================================================================
--- a/source/config/mh-linux
+++ b/source/config/mh-linux
@@ -38,7 +38,7 @@
## Shared object suffix
SO = so
## Non-shared intermediate object suffix
-STATIC_O = ao
+STATIC_O = o
## Compilation rules
%.$(STATIC_O): $(srcdir)/%.c
@@ -0,0 +1,13 @@
diff --git a/preload/configure b/preload/configure
index aab5c77..e20b8f0 100755
--- a/preload/configure
+++ b/preload/configure
@@ -588,7 +588,7 @@ MAKEFLAGS=
PACKAGE_NAME='libiconv'
PACKAGE_TARNAME='libiconv'
PACKAGE_VERSION='0'
-PACKAGE_STRING='libiconv 0'
+PACKAGE_STRING='libiconv0'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -0,0 +1,11 @@
--- config/ltmain.sh.0 2020-11-10 17:25:26.000000000 +0100
+++ config/ltmain.sh 2021-09-11 19:39:36.000000000 +0200
@@ -10768,6 +10768,8 @@
fi
func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
tool_oldlib=$func_to_tool_file_result
+ oldobjs=`for obj in $oldobjs; do echo $obj; done | sort`
+ oldobjs=" `echo $oldobjs`"
eval cmds=\"$old_archive_cmds\"
func_len " $cmds"
+2
View File
@@ -74,6 +74,7 @@ namespace epee
public:
using char_type = std::uint8_t;
using Ch = char_type;
using value_type = char_type;
//! Increase internal buffer by at least `byte_stream_increase` bytes.
byte_stream() noexcept
@@ -86,6 +87,7 @@ namespace epee
~byte_stream() noexcept = default;
byte_stream& operator=(byte_stream&& rhs) noexcept;
std::uint8_t* data() noexcept { return buffer_.get(); }
const std::uint8_t* data() const noexcept { return buffer_.get(); }
std::uint8_t* tellp() const noexcept { return next_write_; }
std::size_t available() const noexcept { return end_ - next_write_; }
+42 -22
View File
@@ -47,6 +47,7 @@
#include <condition_variable>
#include <boost/asio.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/asio/strand.hpp>
#include <boost/asio/steady_timer.hpp>
@@ -64,6 +65,7 @@
#define MONERO_DEFAULT_LOG_CATEGORY "net"
#define ABSTRACT_SERVER_SEND_QUE_MAX_COUNT 1000
#define ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT 100 * 1024 * 1024
namespace epee
{
@@ -76,6 +78,13 @@ namespace net_utils
protected:
virtual ~i_connection_filter(){}
};
struct i_connection_limit
{
virtual bool is_host_limit(const epee::net_utils::network_address &address)=0;
protected:
virtual ~i_connection_limit(){}
};
/************************************************************************/
@@ -100,8 +109,8 @@ namespace net_utils
using ec_t = boost::system::error_code;
using handshake_t = boost::asio::ssl::stream_base::handshake_type;
using io_context_t = boost::asio::io_service;
using strand_t = boost::asio::io_service::strand;
using io_context_t = boost::asio::io_context;
using strand_t = io_context_t::strand;
using socket_t = boost::asio::ip::tcp::socket;
using network_throttle_t = epee::net_utils::network_throttle;
@@ -162,6 +171,7 @@ namespace net_utils
} read;
struct {
std::deque<epee::byte_slice> queue;
std::size_t total_bytes;
bool wait_consume;
} write;
};
@@ -260,20 +270,28 @@ namespace net_utils
struct shared_state : connection_basic_shared_state, t_protocol_handler::config_type
{
shared_state()
: connection_basic_shared_state(), t_protocol_handler::config_type(), pfilter(nullptr), stop_signal_sent(false)
: connection_basic_shared_state(),
t_protocol_handler::config_type(),
pfilter(nullptr),
plimit(nullptr),
response_soft_limit(ABSTRACT_SERVER_SEND_QUE_MAX_BYTES_DEFAULT),
stop_signal_sent(false)
{}
i_connection_filter* pfilter;
i_connection_limit* plimit;
std::size_t response_soft_limit;
bool stop_signal_sent;
};
/// Construct a connection with the given io_service.
explicit connection( boost::asio::io_service& io_service,
/// Construct a connection with the given io_context.
explicit connection( io_context_t& io_context,
std::shared_ptr<shared_state> state,
t_connection_type connection_type,
epee::net_utils::ssl_support_t ssl_support);
explicit connection( boost::asio::ip::tcp::socket&& sock,
explicit connection( io_context_t& io_context,
boost::asio::ip::tcp::socket&& sock,
std::shared_ptr<shared_state> state,
t_connection_type connection_type,
epee::net_utils::ssl_support_t ssl_support);
@@ -306,7 +324,7 @@ namespace net_utils
virtual bool close();
virtual bool call_run_once_service_io();
virtual bool request_callback();
virtual boost::asio::io_service& get_io_service();
virtual io_context_t& get_io_context();
virtual bool add_ref();
virtual bool release();
//------------------------------------------------------
@@ -336,7 +354,7 @@ namespace net_utils
/// serve up files from the given directory.
boosted_tcp_server(t_connection_type connection_type);
explicit boosted_tcp_server(boost::asio::io_service& external_io_service, t_connection_type connection_type);
explicit boosted_tcp_server(boost::asio::io_context& external_io_context, t_connection_type connection_type);
~boosted_tcp_server();
std::map<std::string, t_connection_type> server_type_map;
@@ -349,7 +367,7 @@ namespace net_utils
const std::string port_ipv6 = "", const std::string address_ipv6 = "::", bool use_ipv6 = false, bool require_ipv4 = true,
ssl_options_t ssl_options = ssl_support_t::e_ssl_support_autodetect);
/// Run the server's io_service loop.
/// Run the server's io_context loop.
bool run_server(size_t threads_count, bool wait = true, const boost::thread::attributes& attrs = boost::thread::attributes());
/// wait for service workers stop
@@ -369,6 +387,8 @@ namespace net_utils
size_t get_threads_count(){return m_threads_count;}
void set_connection_filter(i_connection_filter* pfilter);
void set_connection_limit(i_connection_limit* plimit);
void set_response_soft_limit(std::size_t limit);
void set_default_remote(epee::net_utils::network_address remote)
{
@@ -409,7 +429,7 @@ namespace net_utils
return connections_count;
}
boost::asio::io_service& get_io_service(){return io_service_;}
boost::asio::io_context& get_io_context(){return io_context_;}
struct idle_callback_conext_base
{
@@ -417,7 +437,7 @@ namespace net_utils
virtual bool call_handler(){return true;}
idle_callback_conext_base(boost::asio::io_service& io_serice):
idle_callback_conext_base(boost::asio::io_context& io_serice):
m_timer(io_serice)
{}
boost::asio::deadline_timer m_timer;
@@ -426,7 +446,7 @@ namespace net_utils
template <class t_handler>
struct idle_callback_conext: public idle_callback_conext_base
{
idle_callback_conext(boost::asio::io_service& io_serice, t_handler& h, uint64_t period):
idle_callback_conext(boost::asio::io_context& io_serice, t_handler& h, uint64_t period):
idle_callback_conext_base(io_serice),
m_handler(h)
{this->m_period = period;}
@@ -442,7 +462,7 @@ namespace net_utils
template<class t_handler>
bool add_idle_handler(t_handler t_callback, uint64_t timeout_ms)
{
boost::shared_ptr<idle_callback_conext<t_handler>> ptr(new idle_callback_conext<t_handler>(io_service_, t_callback, timeout_ms));
boost::shared_ptr<idle_callback_conext<t_handler>> ptr(new idle_callback_conext<t_handler>(io_context_, t_callback, timeout_ms));
//needed call handler here ?...
ptr->m_timer.expires_from_now(boost::posix_time::milliseconds(ptr->m_period));
ptr->m_timer.async_wait(boost::bind(&boosted_tcp_server<t_protocol_handler>::global_timer_handler<t_handler>, this, ptr));
@@ -461,14 +481,14 @@ namespace net_utils
}
template<class t_handler>
bool async_call(t_handler t_callback)
bool async_call(t_handler&& t_callback)
{
io_service_.post(t_callback);
boost::asio::post(io_context_, std::forward<t_handler>(t_callback));
return true;
}
private:
/// Run the server's io_service loop.
/// Run the server's io_context loop.
bool worker_thread();
/// Handle completion of an asynchronous accept operation.
void handle_accept_ipv4(const boost::system::error_code& e);
@@ -479,18 +499,18 @@ namespace net_utils
const std::shared_ptr<typename connection<t_protocol_handler>::shared_state> m_state;
/// The io_service used to perform asynchronous operations.
/// The io_context used to perform asynchronous operations.
struct worker
{
worker()
: io_service(), work(io_service)
: io_context(), work(io_context.get_executor())
{}
boost::asio::io_service io_service;
boost::asio::io_service::work work;
boost::asio::io_context io_context;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work;
};
std::unique_ptr<worker> m_io_service_local_instance;
boost::asio::io_service& io_service_;
std::unique_ptr<worker> m_io_context_local_instance;
boost::asio::io_context& io_context_;
/// Acceptor used to listen for incoming connections.
boost::asio::ip::tcp::acceptor acceptor_;
+175 -114
View File
@@ -31,11 +31,12 @@
//
#include <boost/asio/post.hpp>
#include <boost/foreach.hpp>
#include <boost/uuid/random_generator.hpp>
#include <boost/chrono.hpp>
#include <boost/utility/value_init.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/date_time/posix_time/posix_time.hpp> // TODO
#include <boost/thread/condition_variable.hpp> // TODO
@@ -145,23 +146,19 @@ namespace net_utils
if (m_state.timers.general.wait_expire) {
m_state.timers.general.cancel_expire = true;
m_state.timers.general.reset_expire = true;
ec_t ec;
m_timers.general.expires_from_now(
m_timers.general.expires_after(
std::min(
duration + (add ? m_timers.general.expires_from_now() : duration_t{}),
duration + (add ? (m_timers.general.expiry() - std::chrono::steady_clock::now()) : duration_t{}),
get_default_timeout()
),
ec
)
);
}
else {
ec_t ec;
m_timers.general.expires_from_now(
m_timers.general.expires_after(
std::min(
duration + (add ? m_timers.general.expires_from_now() : duration_t{}),
duration + (add ? (m_timers.general.expiry() - std::chrono::steady_clock::now()) : duration_t{}),
get_default_timeout()
),
ec
)
);
async_wait_timer();
}
@@ -202,8 +199,7 @@ namespace net_utils
return;
m_state.timers.general.cancel_expire = true;
m_state.timers.general.reset_expire = false;
ec_t ec;
m_timers.general.cancel(ec);
m_timers.general.cancel();
}
template<typename T>
@@ -225,7 +221,8 @@ namespace net_utils
m_state.data.read.buffer.size()
),
boost::asio::transfer_exactly(epee::net_utils::get_ssl_magic_size()),
m_strand.wrap(
boost::asio::bind_executor(
m_strand,
[this, self](const ec_t &ec, size_t bytes_transferred){
std::lock_guard<std::mutex> guard(m_state.lock);
m_state.socket.wait_read = false;
@@ -246,7 +243,8 @@ namespace net_utils
) {
m_state.ssl.enabled = false;
m_state.socket.handle_read = true;
connection_basic::strand_.post(
boost::asio::post(
connection_basic::strand_,
[this, self, bytes_transferred]{
bool success = m_handler.handle_recv(
reinterpret_cast<char *>(m_state.data.read.buffer.data()),
@@ -304,7 +302,8 @@ namespace net_utils
static_cast<shared_state&>(
connection_basic::get_state()
).ssl_options().configure(connection_basic::socket_, handshake);
m_strand.post(
boost::asio::post(
m_strand,
[this, self, on_handshake]{
connection_basic::socket_.async_handshake(
handshake,
@@ -313,7 +312,7 @@ namespace net_utils
m_state.ssl.forced ? 0 :
epee::net_utils::get_ssl_magic_size()
),
m_strand.wrap(on_handshake)
boost::asio::bind_executor(m_strand, on_handshake)
);
}
);
@@ -328,7 +327,7 @@ namespace net_utils
return;
}
auto self = connection<T>::shared_from_this();
if (m_connection_type != e_connection_type_RPC) {
if (speed_limit_is_enabled()) {
auto calc_duration = []{
CRITICAL_REGION_LOCAL(
network_throttle_manager_t::m_lock_get_global_throttle_in
@@ -345,8 +344,7 @@ namespace net_utils
};
const auto duration = calc_duration();
if (duration > duration_t{}) {
ec_t ec;
m_timers.throttle.in.expires_from_now(duration, ec);
m_timers.throttle.in.expires_after(duration);
m_state.timers.throttle.in.wait_expire = true;
m_timers.throttle.in.async_wait([this, self](const ec_t &ec){
std::lock_guard<std::mutex> guard(m_state.lock);
@@ -382,7 +380,7 @@ namespace net_utils
m_conn_context.m_max_speed_down,
speed
);
{
if (speed_limit_is_enabled()) {
CRITICAL_REGION_LOCAL(
network_throttle_manager_t::m_lock_get_global_throttle_in
);
@@ -401,7 +399,8 @@ namespace net_utils
// writes until the connection terminates without deadlocking waiting
// for handle_recv.
m_state.socket.handle_read = true;
connection_basic::strand_.post(
boost::asio::post(
connection_basic::strand_,
[this, self, bytes_transferred]{
bool success = m_handler.handle_recv(
reinterpret_cast<char *>(m_state.data.read.buffer.data()),
@@ -428,17 +427,18 @@ namespace net_utils
m_state.data.read.buffer.data(),
m_state.data.read.buffer.size()
),
m_strand.wrap(on_read)
boost::asio::bind_executor(m_strand, on_read)
);
else
m_strand.post(
boost::asio::post(
m_strand,
[this, self, on_read]{
connection_basic::socket_.async_read_some(
boost::asio::buffer(
m_state.data.read.buffer.data(),
m_state.data.read.buffer.size()
),
m_strand.wrap(on_read)
boost::asio::bind_executor(m_strand, on_read)
);
}
);
@@ -454,7 +454,7 @@ namespace net_utils
return;
}
auto self = connection<T>::shared_from_this();
if (m_connection_type != e_connection_type_RPC) {
if (speed_limit_is_enabled()) {
auto calc_duration = [this]{
CRITICAL_REGION_LOCAL(
network_throttle_manager_t::m_lock_get_global_throttle_out
@@ -473,8 +473,7 @@ namespace net_utils
};
const auto duration = calc_duration();
if (duration > duration_t{}) {
ec_t ec;
m_timers.throttle.out.expires_from_now(duration, ec);
m_timers.throttle.out.expires_after(duration);
m_state.timers.throttle.out.wait_expire = true;
m_timers.throttle.out.async_wait([this, self](const ec_t &ec){
std::lock_guard<std::mutex> guard(m_state.lock);
@@ -498,10 +497,12 @@ namespace net_utils
if (m_state.socket.cancel_write) {
m_state.socket.cancel_write = false;
m_state.data.write.queue.clear();
m_state.data.write.total_bytes = 0;
state_status_check();
}
else if (ec.value()) {
m_state.data.write.queue.clear();
m_state.data.write.total_bytes = 0;
interrupt();
}
else {
@@ -513,7 +514,7 @@ namespace net_utils
m_conn_context.m_max_speed_down,
speed
);
{
if (speed_limit_is_enabled()) {
CRITICAL_REGION_LOCAL(
network_throttle_manager_t::m_lock_get_global_throttle_out
);
@@ -526,8 +527,11 @@ namespace net_utils
start_timer(get_default_timeout(), true);
}
assert(bytes_transferred == m_state.data.write.queue.back().size());
const std::size_t byte_count = m_state.data.write.queue.back().size();
assert(bytes_transferred == byte_count);
m_state.data.write.queue.pop_back();
m_state.data.write.total_bytes -=
std::min(m_state.data.write.total_bytes, byte_count);
m_state.condition.notify_all();
start_write();
}
@@ -539,10 +543,11 @@ namespace net_utils
m_state.data.write.queue.back().data(),
m_state.data.write.queue.back().size()
),
m_strand.wrap(on_write)
boost::asio::bind_executor(m_strand, on_write)
);
else
m_strand.post(
boost::asio::post(
m_strand,
[this, self, on_write]{
boost::asio::async_write(
connection_basic::socket_,
@@ -550,7 +555,7 @@ namespace net_utils
m_state.data.write.queue.back().data(),
m_state.data.write.queue.back().size()
),
m_strand.wrap(on_write)
boost::asio::bind_executor(m_strand, on_write)
);
}
);
@@ -587,10 +592,11 @@ namespace net_utils
terminate();
}
};
m_strand.post(
boost::asio::post(
m_strand,
[this, self, on_shutdown]{
connection_basic::socket_.async_shutdown(
m_strand.wrap(on_shutdown)
boost::asio::bind_executor(m_strand, on_shutdown)
);
}
);
@@ -605,15 +611,13 @@ namespace net_utils
wait_socket = m_state.socket.cancel_handshake = true;
if (m_state.timers.throttle.in.wait_expire) {
m_state.timers.throttle.in.cancel_expire = true;
ec_t ec;
m_timers.throttle.in.cancel(ec);
m_timers.throttle.in.cancel();
}
if (m_state.socket.wait_read)
wait_socket = m_state.socket.cancel_read = true;
if (m_state.timers.throttle.out.wait_expire) {
m_state.timers.throttle.out.cancel_expire = true;
ec_t ec;
m_timers.throttle.out.cancel(ec);
m_timers.throttle.out.cancel();
}
if (m_state.socket.wait_write)
wait_socket = m_state.socket.cancel_write = true;
@@ -671,8 +675,9 @@ namespace net_utils
return;
if (m_state.timers.throttle.out.wait_expire)
return;
if (m_state.socket.wait_write)
return;
// \NOTE See on_terminating() comments
//if (m_state.socket.wait_write)
// return;
if (m_state.socket.wait_shutdown)
return;
if (m_state.protocol.wait_init)
@@ -730,8 +735,13 @@ namespace net_utils
return;
if (m_state.timers.throttle.out.wait_expire)
return;
if (m_state.socket.wait_write)
return;
// Writes cannot be canceled due to `async_write` being a "composed"
// handler. ASIO has new cancellation routines, not available in 1.66, to
// handle this situation. The problem is that if cancel is called after an
// intermediate handler is queued, the op will not check the cancel flag in
// our code, and will instead queue up another write.
//if (m_state.socket.wait_write)
// return;
if (m_state.socket.wait_shutdown)
return;
if (m_state.protocol.wait_init)
@@ -758,6 +768,8 @@ namespace net_utils
std::lock_guard<std::mutex> guard(m_state.lock);
if (m_state.status != status_t::RUNNING || m_state.socket.wait_handshake)
return false;
if (std::numeric_limits<std::size_t>::max() - m_state.data.write.total_bytes < message.size())
return false;
// Wait for the write queue to fall below the max. If it doesn't after a
// randomized delay, drop the connection.
@@ -775,7 +787,14 @@ namespace net_utils
std::uniform_int_distribution<>(5000, 6000)(rng)
);
};
if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT)
// The bytes check intentionally does not include incoming message size.
// This allows for a soft overflow; a single http response will never fail
// this check, but multiple responses could. Clients can avoid this case
// by reading the entire response before making another request. P2P
// should never hit the MAX_BYTES check (when using default values).
if (m_state.data.write.queue.size() <= ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
m_state.data.write.total_bytes <= static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit)
return true;
m_state.data.write.wait_consume = true;
bool success = m_state.condition.wait_for(
@@ -784,14 +803,23 @@ namespace net_utils
[this]{
return (
m_state.status != status_t::RUNNING ||
m_state.data.write.queue.size() <=
ABSTRACT_SERVER_SEND_QUE_MAX_COUNT
(
m_state.data.write.queue.size() <=
ABSTRACT_SERVER_SEND_QUE_MAX_COUNT &&
m_state.data.write.total_bytes <=
static_cast<shared_state&>(connection_basic::get_state()).response_soft_limit
)
);
}
);
m_state.data.write.wait_consume = false;
if (!success) {
terminate();
// synchronize with intermediate writes on `m_strand`
auto self = connection<T>::shared_from_this();
boost::asio::post(m_strand, [this, self] {
std::lock_guard<std::mutex> guard(m_state.lock);
terminate();
});
return false;
}
else
@@ -817,7 +845,9 @@ namespace net_utils
) {
if (!wait_consume())
return false;
const std::size_t byte_count = message.size();
m_state.data.write.queue.emplace_front(std::move(message));
m_state.data.write.total_bytes += byte_count;
start_write();
}
else {
@@ -827,6 +857,7 @@ namespace net_utils
m_state.data.write.queue.emplace_front(
message.take_slice(CHUNK_SIZE)
);
m_state.data.write.total_bytes += m_state.data.write.queue.front().size();
start_write();
}
}
@@ -860,7 +891,7 @@ namespace net_utils
ipv4_network_address{
uint32_t{
boost::asio::detail::socket_ops::host_to_network_long(
endpoint.address().to_v4().to_ulong()
endpoint.address().to_v4().to_uint()
)
},
endpoint.port()
@@ -873,6 +904,13 @@ namespace net_utils
).pfilter;
if (filter && !filter->is_remote_host_allowed(*real_remote))
return false;
auto *limit = static_cast<shared_state&>(
connection_basic::get_state()
).plimit;
if (limit && limit->is_host_limit(*real_remote))
return false;
ec_t ec;
#if !defined(_WIN32) || !defined(__i686)
connection_basic::socket_.next_layer().set_option(
@@ -938,7 +976,8 @@ namespace net_utils
ssl_support_t ssl_support
):
connection(
std::move(socket_t{io_context}),
io_context,
socket_t{io_context},
std::move(shared_state),
connection_type,
ssl_support
@@ -948,15 +987,16 @@ namespace net_utils
template<typename T>
connection<T>::connection(
io_context_t &io_context,
socket_t &&socket,
std::shared_ptr<shared_state> shared_state,
t_connection_type connection_type,
ssl_support_t ssl_support
):
connection_basic(std::move(socket), shared_state, ssl_support),
connection_basic(io_context, std::move(socket), shared_state, ssl_support),
m_handler(this, *shared_state, m_conn_context),
m_connection_type(connection_type),
m_io_context{GET_IO_SERVICE(connection_basic::socket_)},
m_io_context{io_context},
m_strand{m_io_context},
m_timers{m_io_context}
{
@@ -1022,7 +1062,7 @@ namespace net_utils
template<typename T>
bool connection<T>::speed_limit_is_enabled() const
{
return m_connection_type != e_connection_type_RPC;
return m_connection_type == e_connection_type_P2P;
}
template<typename T>
@@ -1075,7 +1115,7 @@ namespace net_utils
return false;
auto self = connection<T>::shared_from_this();
++m_state.protocol.wait_callback;
connection_basic::strand_.post([this, self]{
boost::asio::post(connection_basic::strand_, [this, self]{
m_handler.handle_qued_callback();
std::lock_guard<std::mutex> guard(m_state.lock);
--m_state.protocol.wait_callback;
@@ -1088,7 +1128,7 @@ namespace net_utils
}
template<typename T>
typename connection<T>::io_context_t &connection<T>::get_io_service()
typename connection<T>::io_context_t &connection<T>::get_io_context()
{
return m_io_context;
}
@@ -1128,10 +1168,10 @@ namespace net_utils
template<class t_protocol_handler>
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server( t_connection_type connection_type ) :
m_state(std::make_shared<typename connection<t_protocol_handler>::shared_state>()),
m_io_service_local_instance(new worker()),
io_service_(m_io_service_local_instance->io_service),
acceptor_(io_service_),
acceptor_ipv6(io_service_),
m_io_context_local_instance(new worker()),
io_context_(m_io_context_local_instance->io_context),
acceptor_(io_context_),
acceptor_ipv6(io_context_),
default_remote(),
m_stop_signal_sent(false), m_port(0),
m_threads_count(0),
@@ -1145,11 +1185,11 @@ namespace net_utils
}
template<class t_protocol_handler>
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server(boost::asio::io_service& extarnal_io_service, t_connection_type connection_type) :
boosted_tcp_server<t_protocol_handler>::boosted_tcp_server(boost::asio::io_context& extarnal_io_context, t_connection_type connection_type) :
m_state(std::make_shared<typename connection<t_protocol_handler>::shared_state>()),
io_service_(extarnal_io_service),
acceptor_(io_service_),
acceptor_ipv6(io_service_),
io_context_(extarnal_io_context),
acceptor_(io_context_),
acceptor_ipv6(io_context_),
default_remote(),
m_stop_signal_sent(false), m_port(0),
m_threads_count(0),
@@ -1196,24 +1236,27 @@ namespace net_utils
std::string ipv4_failed = "";
std::string ipv6_failed = "";
boost::asio::ip::tcp::resolver resolver(io_context_);
try
{
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor_.open(endpoint.protocol());
const auto results = resolver.resolve(
address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::canonical_name
);
acceptor_.open(results.begin()->endpoint().protocol());
#if !defined(_WIN32)
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
#endif
acceptor_.bind(endpoint);
acceptor_.bind(*results.begin());
acceptor_.listen();
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
m_port = binded_endpoint.port();
MDEBUG("start accept (IPv4)");
new_connection_.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
new_connection_.reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, m_state->ssl_options().support));
acceptor_.async_accept(new_connection_->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4, this,
boost::asio::placeholders::error));
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv4, this,
boost::asio::placeholders::error));
}
catch (const std::exception &e)
{
@@ -1234,23 +1277,25 @@ namespace net_utils
try
{
if (port_ipv6 == 0) port_ipv6 = port; // default arg means bind to same port as ipv4
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::query::canonical_name);
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor_ipv6.open(endpoint.protocol());
const auto results = resolver.resolve(
address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::canonical_name
);
acceptor_ipv6.open(results.begin()->endpoint().protocol());
#if !defined(_WIN32)
acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
#endif
acceptor_ipv6.set_option(boost::asio::ip::v6_only(true));
acceptor_ipv6.bind(endpoint);
acceptor_ipv6.bind(*results.begin());
acceptor_ipv6.listen();
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_ipv6.local_endpoint();
m_port_ipv6 = binded_endpoint.port();
MDEBUG("start accept (IPv6)");
new_connection_ipv6.reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, m_state->ssl_options().support));
new_connection_ipv6.reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, m_state->ssl_options().support));
acceptor_ipv6.async_accept(new_connection_ipv6->socket(),
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6, this,
boost::asio::placeholders::error));
boost::bind(&boosted_tcp_server<t_protocol_handler>::handle_accept_ipv6, this,
boost::asio::placeholders::error));
}
catch (const std::exception &e)
{
@@ -1314,7 +1359,7 @@ namespace net_utils
{
try
{
io_service_.run();
io_context_.run();
return true;
}
catch(const std::exception& ex)
@@ -1349,6 +1394,20 @@ namespace net_utils
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
void boosted_tcp_server<t_protocol_handler>::set_connection_limit(i_connection_limit* plimit)
{
assert(m_state != nullptr); // always set in constructor
m_state->plimit = plimit;
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
void boosted_tcp_server<t_protocol_handler>::set_response_soft_limit(const std::size_t limit)
{
assert(m_state != nullptr); // always set in constructor
m_state->response_soft_limit = limit;
}
//---------------------------------------------------------------------------------
template<class t_protocol_handler>
bool boosted_tcp_server<t_protocol_handler>::run_server(size_t threads_count, bool wait, const boost::thread::attributes& attrs)
{
TRY_ENTRY();
@@ -1358,7 +1417,7 @@ namespace net_utils
while(!m_stop_signal_sent)
{
// Create a pool of threads to run all of the io_services.
// Create a pool of threads to run all of the io_contexts.
CRITICAL_REGION_BEGIN(m_threads_lock);
for (std::size_t i = 0; i < threads_count; ++i)
{
@@ -1450,7 +1509,7 @@ namespace net_utils
}
connections_.clear();
connections_mutex.unlock();
io_service_.stop();
io_context_.stop();
CATCH_ENTRY_L0("boosted_tcp_server<t_protocol_handler>::send_stop_signal()", void());
}
//---------------------------------------------------------------------------------
@@ -1497,7 +1556,7 @@ namespace net_utils
(*current_new_connection)->setRpcStation(); // hopefully this is not needed actually
}
connection_ptr conn(std::move((*current_new_connection)));
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, conn->get_ssl_support()));
(*current_new_connection).reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, conn->get_ssl_support()));
current_acceptor->async_accept((*current_new_connection)->socket(),
boost::bind(accept_function_pointer, this,
boost::asio::placeholders::error));
@@ -1532,7 +1591,7 @@ namespace net_utils
assert(m_state != nullptr); // always set in constructor
_erro("Some problems at accept: " << e.message() << ", connections_count = " << m_state->sock_count);
misc_utils::sleep_no_w(100);
(*current_new_connection).reset(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, (*current_new_connection)->get_ssl_support()));
(*current_new_connection).reset(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, (*current_new_connection)->get_ssl_support()));
current_acceptor->async_accept((*current_new_connection)->socket(),
boost::bind(accept_function_pointer, this,
boost::asio::placeholders::error));
@@ -1541,9 +1600,9 @@ namespace net_utils
template<class t_protocol_handler>
bool boosted_tcp_server<t_protocol_handler>::add_connection(t_connection_context& out, boost::asio::ip::tcp::socket&& sock, network_address real_remote, epee::net_utils::ssl_support_t ssl_support)
{
if(std::addressof(get_io_service()) == std::addressof(GET_IO_SERVICE(sock)))
if(std::addressof(get_io_context()) == std::addressof(sock.get_executor().context()))
{
connection_ptr conn(new connection<t_protocol_handler>(std::move(sock), m_state, m_connection_type, ssl_support));
connection_ptr conn(new connection<t_protocol_handler>(io_context_, std::move(sock), m_state, m_connection_type, ssl_support));
if(conn->start(false, 1 < m_threads_count, std::move(real_remote)))
{
conn->get_context(out);
@@ -1553,7 +1612,7 @@ namespace net_utils
}
else
{
MWARNING(out << " was not added, socket/io_service mismatch");
MWARNING(out << " was not added, socket/io_context mismatch");
}
return false;
}
@@ -1566,7 +1625,7 @@ namespace net_utils
sock_.open(remote_endpoint.protocol());
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
{
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(bind_ip.c_str()), 0);
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip), 0);
boost::system::error_code ec;
sock_.bind(local_endpoint, ec);
if (ec)
@@ -1661,7 +1720,7 @@ namespace net_utils
{
TRY_ENTRY();
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support) );
connections_mutex.lock();
connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size());
@@ -1671,14 +1730,16 @@ namespace net_utils
bool try_ipv6 = false;
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
boost::asio::ip::tcp::resolver resolver(io_context_);
boost::asio::ip::tcp::resolver::results_type results{};
boost::system::error_code resolve_error;
boost::asio::ip::tcp::resolver::iterator iterator;
try
{
//resolving ipv4 address as ipv6 throws, catch here and move on
iterator = resolver.resolve(query, resolve_error);
results = resolver.resolve(
boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
);
}
catch (const boost::system::system_error& e)
{
@@ -1696,8 +1757,7 @@ namespace net_utils
std::string bind_ip_to_use;
boost::asio::ip::tcp::resolver::iterator end;
if(iterator == end)
if(results.empty())
{
if (!m_use_ipv6)
{
@@ -1717,11 +1777,11 @@ namespace net_utils
if (try_ipv6)
{
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
results = resolver.resolve(
boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
);
iterator = resolver.resolve(query6, resolve_error);
if(iterator == end)
if(results.empty())
{
_erro("Failed to resolve " << adr);
return false;
@@ -1741,6 +1801,8 @@ namespace net_utils
}
const auto iterator = results.begin();
MDEBUG("Trying to connect to " << adr << ":" << port << ", bind_ip = " << bind_ip_to_use);
//boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
@@ -1767,7 +1829,6 @@ namespace net_utils
if (r)
{
new_connection_l->get_context(conn_context);
//new_connection_l.reset(new connection<t_protocol_handler>(io_service_, m_config, m_sock_count, m_pfilter));
}
else
{
@@ -1786,7 +1847,7 @@ namespace net_utils
bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, uint32_t conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support)
{
TRY_ENTRY();
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_service_, m_state, m_connection_type, ssl_support) );
connection_ptr new_connection_l(new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support) );
connections_mutex.lock();
connections_.insert(new_connection_l);
MDEBUG("connections_ size now " << connections_.size());
@@ -1796,14 +1857,16 @@ namespace net_utils
bool try_ipv6 = false;
boost::asio::ip::tcp::resolver resolver(io_service_);
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
boost::asio::ip::tcp::resolver resolver(io_context_);
boost::asio::ip::tcp::resolver::results_type results{};
boost::system::error_code resolve_error;
boost::asio::ip::tcp::resolver::iterator iterator;
try
{
//resolving ipv4 address as ipv6 throws, catch here and move on
iterator = resolver.resolve(query, resolve_error);
results = resolver.resolve(
boost::asio::ip::tcp::v4(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
);
}
catch (const boost::system::system_error& e)
{
@@ -1819,8 +1882,7 @@ namespace net_utils
throw;
}
boost::asio::ip::tcp::resolver::iterator end;
if(iterator == end)
if(results.empty())
{
if (!try_ipv6)
{
@@ -1835,24 +1897,23 @@ namespace net_utils
if (try_ipv6)
{
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
results = resolver.resolve(
boost::asio::ip::tcp::v6(), adr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
);
iterator = resolver.resolve(query6, resolve_error);
if(iterator == end)
if(results.empty())
{
_erro("Failed to resolve " << adr);
return false;
}
}
boost::asio::ip::tcp::endpoint remote_endpoint(*iterator);
boost::asio::ip::tcp::endpoint remote_endpoint(*results.begin());
sock_.open(remote_endpoint.protocol());
if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" )
{
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(bind_ip.c_str()), 0);
boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::make_address(bind_ip.c_str()), 0);
boost::system::error_code ec;
sock_.bind(local_endpoint, ec);
if (ec)
@@ -1864,7 +1925,7 @@ namespace net_utils
}
}
boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_service_));
boost::shared_ptr<boost::asio::deadline_timer> sh_deadline(new boost::asio::deadline_timer(io_context_));
//start deadline
sh_deadline->expires_from_now(boost::posix_time::milliseconds(conn_timeout));
sh_deadline->async_wait([=](const boost::system::error_code& error)
@@ -112,21 +112,20 @@ class connection_basic { // not-templated base class for rapid developmet of som
std::deque<byte_slice> m_send_que;
volatile bool m_is_multithreaded;
/// Strand to ensure the connection's handlers are not called concurrently.
boost::asio::io_service::strand strand_;
boost::asio::io_context::strand strand_;
/// Socket for the connection.
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> socket_;
ssl_support_t m_ssl_support;
public:
// first counter is the ++/-- count of current sockets, the other socket_number is only-increasing ++ number generator
connection_basic(boost::asio::ip::tcp::socket&& socket, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
connection_basic(boost::asio::io_service &io_service, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
connection_basic(boost::asio::io_context &context, boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
connection_basic(boost::asio::io_context &context, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support);
virtual ~connection_basic() noexcept(false);
//! \return `shared_state` object passed in construction (ptr never changes).
connection_basic_shared_state& get_state() noexcept { return *m_state; /* verified in constructor */ }
connection_basic(boost::asio::io_service& io_service, std::atomic<long> &ref_sock_count, std::atomic<long> &sock_number, ssl_support_t ssl);
boost::asio::ip::tcp::socket& socket() { return socket_.next_layer(); }
ssl_support_t get_ssl_support() const { return m_ssl_support; }
@@ -135,7 +134,7 @@ class connection_basic { // not-templated base class for rapid developmet of som
bool handshake(boost::asio::ssl::stream_base::handshake_type type, boost::asio::const_buffer buffer = {})
{
//m_state != nullptr verified in constructor
return m_state->ssl_options().handshake(socket_, type, buffer);
return m_state->ssl_options().handshake(strand_.context(), socket_, type, buffer);
}
template<typename MutableBufferSequence, typename ReadHandler>
@@ -32,6 +32,7 @@
#include <boost/optional/optional.hpp>
#include <string>
#include <unordered_map>
#include "net_utils_base.h"
#include "http_auth.h"
#include "http_base.h"
@@ -54,8 +55,13 @@ namespace net_utils
{
std::string m_folder;
std::vector<std::string> m_access_control_origins;
std::unordered_map<std::string, std::size_t> m_connections;
boost::optional<login> m_user;
size_t m_max_content_length{std::numeric_limits<size_t>::max()};
std::size_t m_connection_count{0};
std::size_t m_max_public_ip_connections{3};
std::size_t m_max_private_ip_connections{25};
std::size_t m_max_connections{100};
critical_section m_lock;
};
@@ -70,7 +76,7 @@ namespace net_utils
typedef http_server_config config_type;
simple_http_connection_handler(i_service_endpoint* psnd_hndlr, config_type& config, t_connection_context& conn_context);
virtual ~simple_http_connection_handler(){}
virtual ~simple_http_connection_handler();
bool release_protocol()
{
@@ -86,10 +92,7 @@ namespace net_utils
{
return true;
}
bool after_init_connection()
{
return true;
}
bool after_init_connection();
virtual bool handle_recv(const void* ptr, size_t cb);
virtual bool handle_request(const http::http_request_info& query_info, http_response_info& response);
@@ -146,6 +149,7 @@ namespace net_utils
protected:
i_service_endpoint* m_psnd_hndlr;
t_connection_context& m_conn_context;
bool m_initialized;
};
template<class t_connection_context>
@@ -212,10 +216,6 @@ namespace net_utils
}
void handle_qued_callback()
{}
bool after_init_connection()
{
return true;
}
private:
//simple_http_connection_handler::config_type m_stub_config;
@@ -208,11 +208,46 @@ namespace net_utils
m_newlines(0),
m_bytes_read(0),
m_psnd_hndlr(psnd_hndlr),
m_conn_context(conn_context)
m_conn_context(conn_context),
m_initialized(false)
{
}
//--------------------------------------------------------------------------------------------
template<class t_connection_context>
simple_http_connection_handler<t_connection_context>::~simple_http_connection_handler()
{
try
{
if (m_initialized)
{
CRITICAL_REGION_LOCAL(m_config.m_lock);
if (m_config.m_connection_count)
--m_config.m_connection_count;
auto elem = m_config.m_connections.find(m_conn_context.m_remote_address.host_str());
if (elem != m_config.m_connections.end())
{
if (elem->second == 1 || elem->second == 0)
m_config.m_connections.erase(elem);
else
--(elem->second);
}
}
}
catch (...)
{}
}
//--------------------------------------------------------------------------------------------
template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::after_init_connection()
{
CRITICAL_REGION_LOCAL(m_config.m_lock);
++m_config.m_connections[m_conn_context.m_remote_address.host_str()];
++m_config.m_connection_count;
m_initialized = true;
return true;
}
//--------------------------------------------------------------------------------------------
template<class t_connection_context>
bool simple_http_connection_handler<t_connection_context>::set_ready_state()
{
@@ -71,7 +71,7 @@
else if((query_info.m_URI == s_pattern) && (cond)) \
{ \
handled = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
uint64_t ticks = epee::misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \
bool parse_res = epee::serialization::load_t_from_json(static_cast<command_type::request&>(req), query_info.m_body); \
if (!parse_res) \
@@ -107,7 +107,7 @@
else if(query_info.m_URI == s_pattern) \
{ \
handled = true; \
uint64_t ticks = misc_utils::get_tick_count(); \
uint64_t ticks = epee::misc_utils::get_tick_count(); \
boost::value_initialized<command_type::request> req; \
bool parse_res = epee::serialization::load_t_from_binary(static_cast<command_type::request&>(req), epee::strspan<uint8_t>(query_info.m_body)); \
if (!parse_res) \
@@ -117,7 +117,7 @@
response_info.m_response_comment = "Bad request"; \
return true; \
} \
uint64_t ticks1 = misc_utils::get_tick_count(); \
uint64_t ticks1 = epee::misc_utils::get_tick_count(); \
boost::value_initialized<command_type::response> resp;\
MINFO(m_conn_context << "calling " << s_pattern); \
bool res = false; \
@@ -129,7 +129,7 @@
response_info.m_response_comment = "Internal Server Error"; \
return true; \
} \
uint64_t ticks2 = misc_utils::get_tick_count(); \
uint64_t ticks2 = epee::misc_utils::get_tick_count(); \
epee::byte_slice buffer; \
epee::serialization::store_t_to_binary(static_cast<command_type::response&>(resp), buffer, 64 * 1024); \
uint64_t ticks3 = epee::misc_utils::get_tick_count(); \
@@ -171,6 +171,13 @@
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \
return true; \
} \
epee::serialization::storage_entry params_; \
params_ = epee::serialization::storage_entry(epee::serialization::section()); \
if(!ps.get_value("params", params_, nullptr)) \
{ \
epee::serialization::section params_section; \
ps.set_value("params", std::move(params_section), nullptr); \
} \
if(false) return true; //just a stub to have "else if"
@@ -33,6 +33,7 @@
#include <boost/thread.hpp>
#include <boost/bind/bind.hpp>
#include "cryptonote_config.h"
#include "net/abstract_tcp_server2.h"
#include "http_protocol_handler.h"
#include "net/http_server_handlers_map2.h"
@@ -44,7 +45,8 @@ namespace epee
{
template<class t_child_class, class t_connection_context = epee::net_utils::connection_context_base>
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>
class http_server_impl_base: public net_utils::http::i_http_server_handler<t_connection_context>,
net_utils::i_connection_limit
{
public:
@@ -52,7 +54,7 @@ namespace epee
: m_net_server(epee::net_utils::e_connection_type_RPC)
{}
explicit http_server_impl_base(boost::asio::io_service& external_io_service)
explicit http_server_impl_base(boost::asio::io_context& external_io_service)
: m_net_server(external_io_service)
{}
@@ -60,8 +62,16 @@ namespace epee
const std::string& bind_ipv6_address = "::", bool use_ipv6 = false, bool require_ipv4 = true,
std::vector<std::string> access_control_origins = std::vector<std::string>(),
boost::optional<net_utils::http::login> user = boost::none,
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect)
net_utils::ssl_options_t ssl_options = net_utils::ssl_support_t::e_ssl_support_autodetect,
const std::size_t max_public_ip_connections = DEFAULT_RPC_MAX_CONNECTIONS_PER_PUBLIC_IP,
const std::size_t max_private_ip_connections = DEFAULT_RPC_MAX_CONNECTIONS_PER_PRIVATE_IP,
const std::size_t max_connections = DEFAULT_RPC_MAX_CONNECTIONS,
const std::size_t response_soft_limit = DEFAULT_RPC_SOFT_LIMIT_SIZE)
{
if (max_connections < max_public_ip_connections)
throw std::invalid_argument{"Max public IP connections cannot be more than max connections"};
if (max_connections < max_private_ip_connections)
throw std::invalid_argument{"Max private IP connections cannot be more than max connections"};
//set self as callback handler
m_net_server.get_config_object().m_phandler = static_cast<t_child_class*>(this);
@@ -75,6 +85,11 @@ namespace epee
m_net_server.get_config_object().m_access_control_origins = std::move(access_control_origins);
m_net_server.get_config_object().m_user = std::move(user);
m_net_server.get_config_object().m_max_public_ip_connections = max_public_ip_connections;
m_net_server.get_config_object().m_max_private_ip_connections = max_private_ip_connections;
m_net_server.get_config_object().m_max_connections = max_connections;
m_net_server.set_response_soft_limit(response_soft_limit);
m_net_server.set_connection_limit(this);
MGINFO("Binding on " << bind_ip << " (IPv4):" << bind_port);
if (use_ipv6)
@@ -131,6 +146,26 @@ namespace epee
}
protected:
virtual bool is_host_limit(const net_utils::network_address& na) override final
{
auto& config = m_net_server.get_config_object();
CRITICAL_REGION_LOCAL(config.m_lock);
if (config.m_max_connections <= config.m_connection_count)
return true;
const bool is_private = na.is_loopback() || na.is_local();
const auto elem = config.m_connections.find(na.host_str());
if (elem != config.m_connections.end())
{
if (is_private)
return config.m_max_private_ip_connections <= elem->second;
else
return config.m_max_public_ip_connections <= elem->second;
}
return false;
}
net_utils::boosted_tcp_server<net_utils::http::http_custom_handler<t_connection_context> > m_net_server;
};
}
@@ -200,7 +200,7 @@ public:
struct anvoke_handler: invoke_response_handler_base
{
anvoke_handler(const callback_t& cb, uint64_t timeout, async_protocol_handler& con, int command)
:m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_service()), m_timer_started(false),
:m_cb(cb), m_timeout(timeout), m_con(con), m_timer(con.m_pservice_endpoint->get_io_context()), m_timer_started(false),
m_cancel_timer_called(false), m_timer_cancelled(false), m_command(command)
{
if(m_con.start_outer_call())
+14 -127
View File
@@ -34,7 +34,7 @@
#include <atomic>
#include <string>
#include <boost/version.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/ssl.hpp>
@@ -158,11 +158,11 @@ namespace net_utils
inline
try_connect_result_t try_connect(const std::string& addr, const std::string& port, std::chrono::milliseconds timeout)
{
m_deadline.expires_from_now(timeout);
m_deadline.expires_after(timeout);
boost::unique_future<boost::asio::ip::tcp::socket> connection = m_connector(addr, port, m_deadline);
for (;;)
{
m_io_service.reset();
m_io_service.restart();
m_io_service.run_one();
if (connection.is_ready())
@@ -178,7 +178,7 @@ namespace net_utils
// SSL Options
if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_enabled || m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{
if (!m_ssl_options.handshake(*m_ssl_socket, boost::asio::ssl::stream_base::client, {}, addr, timeout))
if (!m_ssl_options.handshake(m_io_service, *m_ssl_socket, boost::asio::ssl::stream_base::client, {}, addr, timeout))
{
if (m_ssl_options.support == epee::net_utils::ssl_support_t::e_ssl_support_autodetect)
{
@@ -285,7 +285,7 @@ namespace net_utils
try
{
m_deadline.expires_from_now(timeout);
m_deadline.expires_after(timeout);
// Set up the variable that receives the result of the asynchronous
// operation. The error code is set to would_block to signal that the
@@ -303,7 +303,7 @@ namespace net_utils
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block)
{
m_io_service.reset();
m_io_service.restart();
m_io_service.run_one();
}
@@ -409,7 +409,7 @@ namespace net_utils
// Set a deadline for the asynchronous operation. Since this function uses
// a composed operation (async_read_until), the deadline applies to the
// entire operation, rather than individual reads from the socket.
m_deadline.expires_from_now(timeout);
m_deadline.expires_after(timeout);
// Set up the variable that receives the result of the asynchronous
// operation. The error code is set to would_block to signal that the
@@ -436,7 +436,7 @@ namespace net_utils
// Block until the asynchronous operation has completed.
while (ec == boost::asio::error::would_block && !m_shutdowned)
{
m_io_service.reset();
m_io_service.restart();
m_io_service.run_one();
}
@@ -495,7 +495,7 @@ namespace net_utils
// Set a deadline for the asynchronous operation. Since this function uses
// a composed operation (async_read_until), the deadline applies to the
// entire operation, rather than individual reads from the socket.
m_deadline.expires_from_now(timeout);
m_deadline.expires_after(timeout);
// Set up the variable that receives the result of the asynchronous
// operation. The error code is set to would_block to signal that the
@@ -580,7 +580,7 @@ namespace net_utils
return true;
}
boost::asio::io_service& get_io_service()
boost::asio::io_context& get_io_service()
{
return m_io_service;
}
@@ -607,7 +607,7 @@ namespace net_utils
// Check whether the deadline has passed. We compare the deadline against
// the current time since a new asynchronous operation may have moved the
// deadline before this actor had a chance to run.
if (m_deadline.expires_at() <= std::chrono::steady_clock::now())
if (m_deadline.expiry() <= std::chrono::steady_clock::now())
{
// The deadline has passed. The socket is closed so that any outstanding
// asynchronous operations are cancelled. This allows the blocked
@@ -628,11 +628,11 @@ namespace net_utils
void shutdown_ssl() {
// ssl socket shutdown blocks if server doesn't respond. We close after 2 secs
boost::system::error_code ec = boost::asio::error::would_block;
m_deadline.expires_from_now(std::chrono::milliseconds(2000));
m_deadline.expires_after(std::chrono::milliseconds(2000));
m_ssl_socket->async_shutdown(boost::lambda::var(ec) = boost::lambda::_1);
while (ec == boost::asio::error::would_block)
{
m_io_service.reset();
m_io_service.restart();
m_io_service.run_one();
}
// Ignore "short read" error
@@ -676,7 +676,7 @@ namespace net_utils
}
protected:
boost::asio::io_service m_io_service;
boost::asio::io_context m_io_service;
boost::asio::ssl::context m_ctx;
std::shared_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket>> m_ssl_socket;
std::function<connect_func> m_connector;
@@ -688,119 +688,6 @@ namespace net_utils
std::atomic<uint64_t> m_bytes_sent;
std::atomic<uint64_t> m_bytes_received;
};
/************************************************************************/
/* */
/************************************************************************/
class async_blocked_mode_client: public blocked_mode_client
{
public:
async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service)
{
// No deadline is required until the first socket operation is started. We
// set the deadline to positive infinity so that the actor takes no action
// until a specific deadline is set.
m_send_deadline.expires_at(boost::posix_time::pos_infin);
// Start the persistent actor that checks for deadline expiry.
check_send_deadline();
}
~async_blocked_mode_client()
{
m_send_deadline.cancel();
}
bool shutdown()
{
blocked_mode_client::shutdown();
m_send_deadline.cancel();
return true;
}
inline
bool send(const void* data, size_t sz)
{
try
{
/*
m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout));
// Set up the variable that receives the result of the asynchronous
// operation. The error code is set to would_block to signal that the
// operation is incomplete. Asio guarantees that its asynchronous
// operations will never fail with would_block, so any other value in
// ec indicates completion.
boost::system::error_code ec = boost::asio::error::would_block;
// Start the asynchronous operation itself. The boost::lambda function
// object is used as a callback and will update the ec variable when the
// operation completes. The blocking_udp_client.cpp example shows how you
// can use boost::bind rather than boost::lambda.
boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1);
// Block until the asynchronous operation has completed.
while(ec == boost::asio::error::would_block)
{
m_io_service.run_one();
}*/
boost::system::error_code ec;
size_t writen = write(data, sz, ec);
if (!writen || ec)
{
LOG_PRINT_L3("Problems at write: " << ec.message());
return false;
}else
{
m_send_deadline.expires_at(boost::posix_time::pos_infin);
}
}
catch(const boost::system::system_error& er)
{
LOG_ERROR("Some problems at connect, message: " << er.what());
return false;
}
catch(...)
{
LOG_ERROR("Some fatal problems.");
return false;
}
return true;
}
private:
boost::asio::deadline_timer m_send_deadline;
void check_send_deadline()
{
// Check whether the deadline has passed. We compare the deadline against
// the current time since a new asynchronous operation may have moved the
// deadline before this actor had a chance to run.
if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now())
{
// The deadline has passed. The socket is closed so that any outstanding
// asynchronous operations are cancelled. This allows the blocked
// connect(), read_line() or write_line() functions to return.
LOG_PRINT_L3("Timed out socket");
m_ssl_socket->next_layer().close();
// There is no longer an active deadline. The expiry is set to positive
// infinity so that the actor takes no action until a new deadline is set.
m_send_deadline.expires_at(boost::posix_time::pos_infin);
}
// Put the actor back to sleep.
m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this));
}
};
}
}
+3
View File
@@ -34,6 +34,7 @@
#include <string>
#include <vector>
#include <boost/utility/string_ref.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/filesystem/path.hpp>
@@ -125,6 +126,7 @@ namespace net_utils
\note It is strongly encouraged that clients using `system_ca`
verification provide a non-empty `host` for rfc2818 verification.
\param io_context associated with `socket`.
\param socket Used in SSL handshake and verification
\param type Client or server
\param host This parameter is only used when
@@ -136,6 +138,7 @@ namespace net_utils
\return True if the SSL handshake completes with peer verification
settings. */
bool handshake(
boost::asio::io_context& io_context,
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket,
boost::asio::ssl::stream_base::handshake_type type,
boost::asio::const_buffer buffer = {},
+6 -4
View File
@@ -30,7 +30,7 @@
#define _NET_UTILS_BASE_H_
#include <boost/uuid/uuid.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/address_v6.hpp>
#include <typeinfo>
#include <type_traits>
@@ -47,10 +47,12 @@
#define MAKE_IP( a1, a2, a3, a4 ) (a1|(a2<<8)|(a3<<16)|(((uint32_t)a4)<<24))
#endif
/* Use the below function carefully. The executor and io_context are slightly
different concepts. */
#if BOOST_VERSION >= 107000
#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context())
#define MONERO_GET_EXECUTOR(type) type . get_executor()
#else
#define GET_IO_SERVICE(s) ((s).get_io_service())
#define MONERO_GET_EXECUTOR(type) type . get_io_context()
#endif
namespace net
@@ -443,7 +445,7 @@ namespace net_utils
virtual bool send_done()=0;
virtual bool call_run_once_service_io()=0;
virtual bool request_callback()=0;
virtual boost::asio::io_service& get_io_service()=0;
virtual boost::asio::io_context& get_io_context()=0;
//protect from deletion connection object(with protocol instance) during external call "invoke"
virtual bool add_ref()=0;
virtual bool release()=0;
@@ -46,13 +46,13 @@ namespace net_utils
class network_throttle : public i_network_throttle {
private:
public:
struct packet_info {
size_t m_size; // octets sent. Summary for given small-window (e.g. for all packaged in 1 second)
packet_info();
};
private:
network_speed_bps m_target_speed;
size_t m_network_add_cost; // estimated add cost of headers
size_t m_network_minimal_segment; // estimated minimal cost of sending 1 byte to round up to
@@ -98,16 +98,18 @@ public: \
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name) \
epee::serialization::selector<is_store>::serialize_t_val_as_blob(this_ref.varialble, stg, hparent_section, val_name);
#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, val_name) \
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name)
#define KV_SERIALIZE_VAL_POD_AS_BLOB_N(variable, val_name) \
static_assert(std::is_trivially_copyable<decltype(this_ref.variable)>(), "t_type must be a trivially copyable type."); \
static_assert(std::is_standard_layout<decltype(this_ref.variable)>(), "t_type must be a standard layout type."); \
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(variable, val_name)
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, val_name, default_value) \
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(variable, val_name, default_value) \
do { \
static_assert(std::is_pod<decltype(this_ref.varialble)>::value, "t_type must be a POD type."); \
bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, val_name); \
static_assert(std::is_trivially_copyable<decltype(this_ref.variable)>(), "t_type must be a trivially copyable type."); \
static_assert(std::is_standard_layout<decltype(this_ref.variable)>(), "t_type must be a standard layout type."); \
bool ret = KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(variable, val_name) \
if (!ret) \
epee::serialize_default(this_ref.varialble, default_value); \
epee::serialize_default(this_ref.variable, default_value); \
} while(0);
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, val_name) \
@@ -118,7 +120,7 @@ public: \
#define KV_SERIALIZE(varialble) KV_SERIALIZE_N(varialble, #varialble)
#define KV_SERIALIZE_VAL_POD_AS_BLOB(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_N(varialble, #varialble)
#define KV_SERIALIZE_VAL_POD_AS_BLOB_OPT(varialble, def) KV_SERIALIZE_VAL_POD_AS_BLOB_OPT_N(varialble, #varialble, def)
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_pod compile time check
#define KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(varialble) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE_N(varialble, #varialble) //skip is_trivially_copyable and is_standard_layout compile time check
#define KV_SERIALIZE_CONTAINER_POD_AS_BLOB(varialble) KV_SERIALIZE_CONTAINER_POD_AS_BLOB_N(varialble, #varialble)
#define KV_SERIALIZE_OPT(variable,default_value) KV_SERIALIZE_OPT_N(variable, #variable, default_value)
+13 -10
View File
@@ -133,17 +133,14 @@ namespace epee
return {src.data(), src.size()};
}
template<typename T>
constexpr bool has_padding() noexcept
{
return !std::is_standard_layout<T>() || alignof(T) != 1;
}
//! \return Cast data from `src` as `span<const std::uint8_t>`.
template<typename T>
span<const std::uint8_t> to_byte_span(const span<const T> src) noexcept
{
static_assert(!has_padding<T>(), "source type may have padding");
static_assert(!std::is_empty<T>(), "empty value types will not work -> sizeof == 1");
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
static_assert(alignof(T) == 1, "type may have padding");
return {reinterpret_cast<const std::uint8_t*>(src.data()), src.size_bytes()};
}
@@ -153,7 +150,9 @@ namespace epee
{
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");
static_assert(std::is_standard_layout<value_type>(), "value type must have standard layout");
static_assert(std::is_trivially_copyable<value_type>(), "value type must be trivially copyable");
static_assert(alignof(value_type) == 1, "value type may have padding");
return {reinterpret_cast<std::uint8_t*>(src.data()), src.size() * sizeof(value_type)};
}
@@ -162,7 +161,9 @@ namespace epee
span<const std::uint8_t> as_byte_span(const T& src) noexcept
{
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
static_assert(!has_padding<T>(), "source type may have padding");
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
static_assert(alignof(T) == 1, "type may have padding");
return {reinterpret_cast<const std::uint8_t*>(std::addressof(src)), sizeof(T)};
}
@@ -171,7 +172,9 @@ namespace epee
span<std::uint8_t> as_mut_byte_span(T& src) noexcept
{
static_assert(!std::is_empty<T>(), "empty types will not work -> sizeof == 1");
static_assert(!has_padding<T>(), "source type may have padding");
static_assert(std::is_standard_layout<T>(), "type must have standard layout");
static_assert(std::is_trivially_copyable<T>(), "type must be trivially copyable");
static_assert(alignof(T) == 1, "type may have padding");
return {reinterpret_cast<std::uint8_t*>(std::addressof(src)), sizeof(T)};
}
@@ -38,6 +38,7 @@
#include <boost/numeric/conversion/bounds.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/numeric/conversion/bounds.hpp>
#include <typeinfo>
#include <iomanip>
+8 -10
View File
@@ -31,6 +31,7 @@
#include "mlocker.h"
#include <boost/utility/string_ref.hpp>
#include <boost/algorithm/string.hpp>
#include <sstream>
#include <string>
#include <cstdint>
@@ -69,23 +70,17 @@ namespace string_tools
#ifdef _WIN32
std::string get_current_module_path();
#endif
bool set_module_name_and_folder(const std::string& path_to_process_);
bool trim_left(std::string& str);
bool trim_right(std::string& str);
void set_module_name_and_folder(const std::string& path_to_process_);
//----------------------------------------------------------------------------
inline std::string& trim(std::string& str)
{
trim_left(str);
trim_right(str);
boost::trim(str);
return str;
}
//----------------------------------------------------------------------------
inline std::string trim(const std::string& str_)
inline std::string trim(const std::string& str)
{
std::string str = str_;
trim_left(str);
trim_right(str);
return str;
return boost::trim_copy(str);
}
std::string pad_string(std::string s, size_t n, char c = ' ', bool prepend = false);
@@ -94,6 +89,7 @@ namespace string_tools
std::string pod_to_hex(const t_pod_type& s)
{
static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type");
static_assert(alignof(t_pod_type) == 1, "type may have padding");
return to_hex::string(as_byte_span(s));
}
//----------------------------------------------------------------------------
@@ -101,6 +97,8 @@ namespace string_tools
bool hex_to_pod(const boost::string_ref hex_str, t_pod_type& s)
{
static_assert(std::is_standard_layout<t_pod_type>(), "expected standard layout type");
static_assert(alignof(t_pod_type) == 1, "type may have padding");
static_assert(std::is_trivially_copyable<t_pod_type>(), "type must be trivially copyable");
return from_hex::to_buffer(as_mut_byte_span(s), hex_str);
}
//----------------------------------------------------------------------------
@@ -135,6 +135,13 @@ namespace http
http::url_content parsed{};
const bool r = parse_url(address, parsed);
CHECK_AND_ASSERT_MES(r, false, "failed to parse url: " << address);
if (parsed.port == 0)
{
if (parsed.schema == "http")
parsed.port = 80;
else if (parsed.schema == "https")
parsed.port = 443;
}
set_server(std::move(parsed.host), std::to_string(parsed.port), std::move(user), std::move(ssl_options));
return true;
}
+6 -2
View File
@@ -152,7 +152,11 @@ namespace epee
{
std::size_t space_needed = 0;
for (const auto& source : sources)
{
if (std::numeric_limits<std::size_t>::max() - space_needed < source.size())
throw std::bad_alloc{};
space_needed += source.size();
}
if (space_needed)
{
@@ -162,9 +166,9 @@ namespace epee
for (const auto& source : sources)
{
assert(source.size() <= out.size()); // see check above
std::memcpy(out.data(), source.data(), source.size());
if (out.remove_prefix(source.size()) < source.size())
throw std::bad_alloc{}; // size_t overflow on space_needed
out.remove_prefix(source.size());
}
storage_ = std::move(storage);
}
+6 -12
View File
@@ -46,12 +46,6 @@
// TODO:
#include "net/network_throttle-detail.hpp"
#if BOOST_VERSION >= 107000
#define GET_IO_SERVICE(s) ((boost::asio::io_context&)(s).get_executor().context())
#else
#define GET_IO_SERVICE(s) ((s).get_io_service())
#endif
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.conn"
@@ -127,12 +121,12 @@ connection_basic_pimpl::connection_basic_pimpl(const std::string &name) : m_thro
int connection_basic_pimpl::m_default_tos;
// methods:
connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
connection_basic::connection_basic(boost::asio::io_context &io_context, boost::asio::ip::tcp::socket&& sock, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
:
m_state(std::move(state)),
mI( new connection_basic_pimpl("peer") ),
strand_(GET_IO_SERVICE(sock)),
socket_(GET_IO_SERVICE(sock), get_context(m_state.get())),
strand_(io_context),
socket_(io_context, get_context(m_state.get())),
m_want_close_connection(false),
m_was_shutdown(false),
m_is_multithreaded(false),
@@ -152,12 +146,12 @@ connection_basic::connection_basic(boost::asio::ip::tcp::socket&& sock, std::sha
_note("Spawned connection #"<<mI->m_peer_number<<" to " << remote_addr_str << " currently we have sockets count:" << m_state->sock_count);
}
connection_basic::connection_basic(boost::asio::io_service &io_service, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
connection_basic::connection_basic(boost::asio::io_context &io_context, std::shared_ptr<connection_basic_shared_state> state, ssl_support_t ssl_support)
:
m_state(std::move(state)),
mI( new connection_basic_pimpl("peer") ),
strand_(io_service),
socket_(io_service, get_context(m_state.get())),
strand_(io_context),
socket_(io_context, get_context(m_state.get())),
m_want_close_connection(false),
m_was_shutdown(false),
m_is_multithreaded(false),
+3 -2
View File
@@ -176,11 +176,12 @@ void mlog_configure(const std::string &filename_base, bool console, const std::s
std::vector<boost::filesystem::path> found_files;
const boost::filesystem::directory_iterator end_itr;
const boost::filesystem::path filename_base_path(filename_base);
const std::string filename_base_name = filename_base_path.filename().string();
const boost::filesystem::path parent_path = filename_base_path.has_parent_path() ? filename_base_path.parent_path() : ".";
for (boost::filesystem::directory_iterator iter(parent_path); iter != end_itr; ++iter)
{
const std::string filename = iter->path().string();
if (filename.size() >= filename_base.size() && std::memcmp(filename.data(), filename_base.data(), filename_base.size()) == 0)
const std::string filename = iter->path().filename().string();
if (filename.size() >= filename_base_name.size() && std::memcmp(filename.data(), filename_base_name.data(), filename_base_name.size()) == 0)
{
found_files.push_back(iter->path());
}
+29 -20
View File
@@ -4,22 +4,38 @@ namespace epee
{
namespace net_utils
{
namespace
{
struct new_connection
{
boost::promise<boost::asio::ip::tcp::socket> result_;
boost::asio::ip::tcp::socket socket_;
template<typename T>
explicit new_connection(T&& executor)
: result_(), socket_(std::forward<T>(executor))
{}
};
}
boost::unique_future<boost::asio::ip::tcp::socket>
direct_connect::operator()(const std::string& addr, const std::string& port, boost::asio::steady_timer& timeout) const
{
// Get a list of endpoints corresponding to the server name.
//////////////////////////////////////////////////////////////////////////
boost::asio::ip::tcp::resolver resolver(GET_IO_SERVICE(timeout));
boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
boost::asio::ip::tcp::resolver resolver(MONERO_GET_EXECUTOR(timeout));
bool try_ipv6 = false;
boost::asio::ip::tcp::resolver::iterator iterator;
boost::asio::ip::tcp::resolver::iterator end;
boost::asio::ip::tcp::resolver::results_type results{};
boost::system::error_code resolve_error;
try
{
iterator = resolver.resolve(query, resolve_error);
if(iterator == end) // Documentation states that successful call is guaranteed to be non-empty
results = resolver.resolve(
boost::asio::ip::tcp::v4(), addr, port, boost::asio::ip::tcp::resolver::canonical_name, resolve_error
);
if (results.empty())
{
// if IPv4 resolution fails, try IPv6. Unintentional outgoing IPv6 connections should only
// be possible if for some reason a hostname was given and that hostname fails IPv4 resolution,
@@ -37,27 +53,20 @@ namespace net_utils
}
try_ipv6 = true;
}
if (try_ipv6)
{
boost::asio::ip::tcp::resolver::query query6(boost::asio::ip::tcp::v6(), addr, port, boost::asio::ip::tcp::resolver::query::canonical_name);
iterator = resolver.resolve(query6);
if (iterator == end)
results = resolver.resolve(
boost::asio::ip::tcp::v6(), addr, port, boost::asio::ip::tcp::resolver::canonical_name
);
if (results.empty())
throw boost::system::system_error{boost::asio::error::fault, "Failed to resolve " + addr};
}
//////////////////////////////////////////////////////////////////////////
struct new_connection
{
boost::promise<boost::asio::ip::tcp::socket> result_;
boost::asio::ip::tcp::socket socket_;
explicit new_connection(boost::asio::io_service& io_service)
: result_(), socket_(io_service)
{}
};
const auto shared = std::make_shared<new_connection>(GET_IO_SERVICE(timeout));
const auto shared = std::make_shared<new_connection>(MONERO_GET_EXECUTOR(timeout));
timeout.async_wait([shared] (boost::system::error_code error)
{
if (error != boost::system::errc::operation_canceled && shared && shared->socket_.is_open())
@@ -66,7 +75,7 @@ namespace net_utils
shared->socket_.close();
}
});
shared->socket_.async_connect(*iterator, [shared] (boost::system::error_code error)
shared->socket_.async_connect(*results.begin(), [shared] (boost::system::error_code error)
{
if (shared)
{
+15 -7
View File
@@ -29,6 +29,7 @@
#include <string.h>
#include <thread>
#include <boost/asio/post.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/cerrno.hpp>
#include <boost/filesystem/operations.hpp>
@@ -45,6 +46,13 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "net.ssl"
#if BOOST_VERSION >= 107300
#define MONERO_HOSTNAME_VERIFY boost::asio::ssl::host_name_verification
#else
#define MONERO_HOSTNAME_VERIFY boost::asio::ssl::rfc2818_verification
#endif
// openssl genrsa -out /tmp/KEY 4096
// openssl req -new -key /tmp/KEY -out /tmp/REQ
// openssl x509 -req -days 999999 -sha256 -in /tmp/REQ -signkey /tmp/KEY -out /tmp/CERT
@@ -526,7 +534,7 @@ void ssl_options_t::configure(
// preverified means it passed system or user CA check. System CA is never loaded
// when fingerprints are whitelisted.
const bool verified = preverified &&
(verification != ssl_verification_t::system_ca || host.empty() || boost::asio::ssl::rfc2818_verification(host)(preverified, ctx));
(verification != ssl_verification_t::system_ca || host.empty() || MONERO_HOSTNAME_VERIFY(host)(preverified, ctx));
if (!verified && !has_fingerprint(ctx))
{
@@ -544,6 +552,7 @@ void ssl_options_t::configure(
}
bool ssl_options_t::handshake(
boost::asio::io_context& io_context,
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> &socket,
boost::asio::ssl::stream_base::handshake_type type,
boost::asio::const_buffer buffer,
@@ -555,12 +564,11 @@ bool ssl_options_t::handshake(
auto start_handshake = [&]{
using ec_t = boost::system::error_code;
using timer_t = boost::asio::steady_timer;
using strand_t = boost::asio::io_service::strand;
using strand_t = boost::asio::io_context::strand;
using socket_t = boost::asio::ip::tcp::socket;
auto &io_context = GET_IO_SERVICE(socket);
if (io_context.stopped())
io_context.reset();
io_context.restart();
strand_t strand(io_context);
timer_t deadline(io_context, timeout);
@@ -595,13 +603,13 @@ bool ssl_options_t::handshake(
state.result = ec;
if (!state.cancel_handshake) {
state.cancel_timer = true;
ec_t ec;
deadline.cancel(ec);
deadline.cancel();
}
};
deadline.async_wait(on_timer);
strand.post(
boost::asio::post(
strand,
[&]{
socket.async_handshake(
type,
+20 -8
View File
@@ -46,7 +46,7 @@
#include "misc_log_ex.h"
#include <boost/chrono.hpp>
#include "misc_language.h"
#include <sstream>
#include <fstream>
#include <iomanip>
#include <algorithm>
@@ -186,6 +186,23 @@ void network_throttle::handle_trafic_exact(size_t packet_size)
_handle_trafic_exact(packet_size, packet_size);
}
namespace
{
struct output_history
{
const boost::circular_buffer< network_throttle::packet_info >& history;
};
std::ostream& operator<<(std::ostream& out, const output_history& source)
{
out << '[';
for (auto sample: source.history)
out << sample.m_size << ' ';
out << ']';
return out;
}
}
void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_size)
{
tick();
@@ -196,14 +213,11 @@ void network_throttle::_handle_trafic_exact(size_t packet_size, size_t orginal_s
m_total_packets++;
m_total_bytes += packet_size;
std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends;
std::string history_str = oss.str();
MTRACE("Throttle " << m_name << ": packet of ~"<<packet_size<<"b " << " (from "<<orginal_size<<" b)"
<< " Speed AVG=" << std::setw(4) << ((long int)(cts .average/1024)) <<"[w="<<cts .window<<"]"
<< " " << std::setw(4) << ((long int)(cts2.average/1024)) <<"[w="<<cts2.window<<"]"
<<" / " << " Limit="<< ((long int)(m_target_speed/1024)) <<" KiB/sec "
<< " " << history_str
<< " " << output_history{m_history}
);
}
@@ -289,8 +303,6 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc
}
if (dbg) {
std::ostringstream oss; oss << "["; for (auto sample: m_history) oss << sample.m_size << " "; oss << "]" << std::ends;
std::string history_str = oss.str();
MTRACE((cts.delay > 0 ? "SLEEP" : "")
<< "dbg " << m_name << ": "
<< "speed is A=" << std::setw(8) <<cts.average<<" vs "
@@ -300,7 +312,7 @@ void network_throttle::calculate_times(size_t packet_size, calculate_times_struc
<< "E="<< std::setw(8) << E << " (Enow="<<std::setw(8)<<Enow<<") "
<< "M=" << std::setw(8) << M <<" W="<< std::setw(8) << cts.window << " "
<< "R=" << std::setw(8) << cts.recomendetDataSize << " Wgood" << std::setw(8) << Wgood << " "
<< "History: " << std::setw(8) << history_str << " "
<< "History: " << std::setw(8) << output_history{m_history} << " "
<< "m_last_sample_time=" << std::setw(8) << m_last_sample_time
);
+26 -55
View File
@@ -38,9 +38,12 @@
#include <cstdlib>
#include <string>
#include <type_traits>
#include <system_error>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/utility/string_ref.hpp>
#include <boost/filesystem.hpp>
#include "misc_log_ex.h"
#include "storages/parserse_base_utils.h"
#include "hex.h"
@@ -157,46 +160,20 @@ namespace string_tools
return pname;
}
#endif
bool set_module_name_and_folder(const std::string& path_to_process_)
{
std::string path_to_process = path_to_process_;
void set_module_name_and_folder(const std::string& path_to_process_)
{
boost::filesystem::path path_to_process = path_to_process_;
#ifdef _WIN32
path_to_process = get_current_module_path();
#endif
std::string::size_type a = path_to_process.rfind( '\\' );
if(a == std::string::npos )
{
a = path_to_process.rfind( '/' );
}
if ( a != std::string::npos )
{
get_current_module_name() = path_to_process.substr(a+1, path_to_process.size());
get_current_module_folder() = path_to_process.substr(0, a);
return true;
}else
return false;
}
get_current_module_name() = path_to_process.filename().string();
get_current_module_folder() = path_to_process.parent_path().string();
}
//----------------------------------------------------------------------------
bool trim_left(std::string& str)
{
for(std::string::iterator it = str.begin(); it!= str.end() && isspace(static_cast<unsigned char>(*it));)
str.erase(str.begin());
return true;
}
//----------------------------------------------------------------------------
bool trim_right(std::string& str)
{
for(std::string::reverse_iterator it = str.rbegin(); it!= str.rend() && isspace(static_cast<unsigned char>(*it));)
str.erase( --((it++).base()));
return true;
}
//----------------------------------------------------------------------------
std::string pad_string(std::string s, size_t n, char c, bool prepend)
{
if (s.size() < n)
@@ -209,28 +186,22 @@ namespace string_tools
return s;
}
std::string get_extension(const std::string& str)
{
std::string res;
std::string::size_type pos = str.rfind('.');
if(std::string::npos == pos)
return res;
res = str.substr(pos+1, str.size()-pos);
return res;
}
//----------------------------------------------------------------------------
std::string cut_off_extension(const std::string& str)
{
std::string res;
std::string::size_type pos = str.rfind('.');
if(std::string::npos == pos)
return str;
std::string get_extension(const std::string& str)
{
std::string ext_with_dot = boost::filesystem::path(str).extension().string();
if (ext_with_dot.empty())
return {};
return ext_with_dot.erase(0, 1);
}
//----------------------------------------------------------------------------
std::string cut_off_extension(const std::string& str)
{
return boost::filesystem::path(str).replace_extension("").string();
}
res = str.substr(0, pos);
return res;
}
//----------------------------------------------------------------------------
#ifdef _WIN32
std::wstring utf8_to_utf16(const std::string& str)
{
Vendored Submodule
+1
Submodule external/mx25519 added at 84ca1290fa
+6 -6
View File
@@ -4,6 +4,12 @@
TAG=`git tag -l --points-at HEAD`
COMMIT=`git rev-parse --short=9 HEAD`
# Build the 64-bit Windows release
USE_DEVICE_TREZOR=OFF make depends target=x86_64-w64-mingw32 -j12
pushd ./build/x86_64-w64-mingw32/release/bin > /dev/null
zip -ur ~/releases/salvium-${TAG}-win64.zip salviumd.exe salvium-wallet-cli.exe salvium-wallet-rpc.exe
popd > /dev/null
# Build the 64-bit Apple Silicon release
USE_DEVICE_TREZOR=OFF make depends target=aarch64-apple-darwin -j12
pushd ./build/aarch64-apple-darwin/release/bin > /dev/null
@@ -22,10 +28,4 @@ pushd ./build/x86_64-linux-gnu/release/bin > /dev/null
zip -ur ~/releases/salvium-${TAG}-linux-x86_64.zip salviumd salvium-wallet-cli salvium-wallet-rpc
popd > /dev/null
# Build the 64-bit Windows release
USE_DEVICE_TREZOR=OFF make depends target=x86_64-w64-mingw32 -j12
pushd ./build/x86_64-w64-mingw32/release/bin > /dev/null
zip -ur ~/releases/salvium-${TAG}-win64.zip salviumd.exe salvium-wallet-cli.exe salvium-wallet-rpc.exe
popd > /dev/null
# Finish
+15 -9
View File
@@ -267,8 +267,9 @@ 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
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
)
{
const block &blk = blck.first;
@@ -295,7 +296,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
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)
if (blk.miner_tx.version >= 2)
{
num_rct_outs += blk.miner_tx.vout.size();
@@ -309,8 +310,8 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
}
std::map<std::string, int64_t> slippage_counts;
uint64_t yield_total = 0;
if (blk.protocol_tx.version == 2)
uint64_t audit_total = 0, yield_total = 0;
if (blk.protocol_tx.version >= 2)
{
num_rct_outs += blk.protocol_tx.vout.size();
@@ -355,11 +356,16 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
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;
}
// Is this an AUDIT TX?
if (tx.first.type == cryptonote::transaction_type::AUDIT) {
audit_total += tx.first.amount_burnt;
}
// Is this a STAKE TX?
if (tx.first.type == cryptonote::transaction_type::STAKE) {
yield_total += tx.first.amount_burnt;
}
++tx_i;
}
@@ -410,7 +416,7 @@ uint64_t BlockchainDB::add_block( const std::pair<block, blobdata>& blck
// 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, num_rct_outs_by_asset_type, blk_hash, slippage_total, yield_total, nettype, ybi);
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, audit_total, nettype, ybi, abi);
TIME_MEASURE_FINISH(time1);
time_add_block1 += time1;
+9 -3
View File
@@ -430,8 +430,10 @@ private:
const crypto::hash& blk_hash,
uint64_t slippage_total,
uint64_t yield_total,
const cryptonote::network_type& nettype,
cryptonote::yield_block_info& ybi
uint64_t audit_total,
const cryptonote::network_type nettype,
cryptonote::yield_block_info& ybi,
cryptonote::audit_block_info& abi
) = 0;
/**
@@ -884,8 +886,9 @@ public:
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, const std::vector<std::pair<transaction, blobdata>>& txs
, const cryptonote::network_type& nettype
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
);
/**
@@ -1915,6 +1918,9 @@ public:
*/
virtual uint64_t get_database_size() const = 0;
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const = 0;
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const = 0;
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const = 0;
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const = 0;
+405 -37
View File
@@ -29,14 +29,18 @@
#include "db_lmdb.h"
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
#include <boost/circular_buffer.hpp>
#include <memory> // std::unique_ptr
#include <cstring> // memcpy
#ifdef WIN32
#include <winioctl.h>
#endif
#include "string_tools.h"
#include "file_io_utils.h"
#include "common/util.h"
#include "common/pruning.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
@@ -215,6 +219,9 @@ namespace
* yield_block_data block height {slippage_coins, locked_coins, lc_total, network_health}
* yield_tx_data block height {txn hash, locked_coins, return_address}
*
* audit_block_data block height {locked_coins, lc_total}
* audit_tx_data block height {txn hash, locked_coins, return_address}
*
* Note: where the data items are of uniform size, DUPFIXED tables have
* been used to save space. In most of these cases, a dummy "zerokval"
* key is used when accessing the table; the Key listed above will be
@@ -289,6 +296,8 @@ const char* const LMDB_CIRC_SUPPLY_TALLY = "circ_supply_tally";
*/
const char* const LMDB_YIELD_TXS = "yield_txs";
const char* const LMDB_YIELD_BLOCKS = "yield_blocks";
const char* const LMDB_AUDIT_TXS = "audit_txs";
const char* const LMDB_AUDIT_BLOCKS = "audit_blocks";
const char zerokey[8] = {0};
const MDB_val zerokval = { sizeof(zerokey), (void *)zerokey };
@@ -800,6 +809,75 @@ estim:
return threshold_size;
}
int BlockchainLMDB::get_audit_block_info(const uint64_t height, audit_block_info& abi) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
// Clear the ABI, just in case
std::memset(&abi, 0, sizeof(struct audit_block_info));
// Query for the matured AUDIT_BLOCK_INFO information
TXN_PREFIX_RDONLY();
RCURSOR(audit_blocks);
MDB_val v;
MDB_val_set(k, height);
int ret = mdb_cursor_get(m_cur_audit_blocks, &k, &v, MDB_SET);
if (ret == MDB_NOTFOUND) {
LOG_ERROR("Failed to locate ABI for block height " << height);
return ret;
}
if (ret)
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit block info: ", ret).c_str()));
audit_block_info *p = (audit_block_info*)v.mv_data;
abi = *p;
TXN_POSTFIX_RDONLY();
// Return success to caller
return ret;
}
int BlockchainLMDB::get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
// Clear the container
ati_container.clear();
// Query for the (presumably matured) AUDIT_TX_INFO information (we actually reuse YIELD_TX_INFO for this)
TXN_PREFIX_RDONLY();
RCURSOR(audit_txs);
MDB_val v;
MDB_val_set(k, height);
MDB_cursor_op op = MDB_SET;
while (1)
{
int ret = mdb_cursor_get(m_cur_audit_txs, &k, &v, op);
op = MDB_NEXT_DUP;
if (ret == MDB_NOTFOUND)
break;
if (ret)
throw0(DB_ERROR(lmdb_error("Failed to enumerate audit TX info: ", ret).c_str()));
// Get the data
yield_tx_info *p = (yield_tx_info*)v.mv_data;
// Push result back into the container
ati_container.emplace_back(*p);
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
ati_container.back().block_height = height;
}
TXN_POSTFIX_RDONLY();
// Return success to caller
return 0;
}
int BlockchainLMDB::get_yield_block_info(const uint64_t height, yield_block_info& ybi) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -855,9 +933,12 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
if (ret)
throw0(DB_ERROR(lmdb_error("Failed to enumerate yield TX info: ", ret).c_str()));
// Push result back into the container
// Get the data
yield_tx_info *p = (yield_tx_info*)v.mv_data;
// Push result back into the container
yti_container.emplace_back(*p);
// Update the height retrospectively (because the DB stores the count of elements there to handle duplicates, because it's rubbish)
yti_container.back().block_height = height;
}
TXN_POSTFIX_RDONLY();
@@ -866,7 +947,7 @@ int BlockchainLMDB::get_yield_tx_info(const uint64_t height, std::vector<yield_t
return 0;
}
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, const cryptonote::network_type& nettype, cryptonote::yield_block_info& ybi)
void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t long_term_block_weight, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, uint64_t num_rct_outs, oracle::asset_type_counts& cum_rct_by_asset_type, const crypto::hash& blk_hash, uint64_t slippage_total, uint64_t yield_total, uint64_t audit_total, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -896,6 +977,18 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
int result = 0;
// Create the AUDIT_BLOCK_INFO instance for this block
CURSOR(audit_blocks)
abi.block_height = m_height;
abi.locked_coins_this_block = audit_total;
// Put the YBI into the table
MDB_val_set(key, m_height);
MDB_val_set(abi_val, abi);
result = mdb_cursor_put(m_cur_audit_blocks, &key, &abi_val, MDB_APPEND);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to add ABI to db: ", result).c_str()));
CURSOR(yield_blocks)
yield_block_info ybi_matured, ybi_prev;
uint64_t yield_lock_period = cryptonote::get_config(nettype).STAKE_LOCK_PERIOD;
@@ -932,7 +1025,6 @@ void BlockchainLMDB::add_block(const block& blk, size_t block_weight, uint64_t l
ybi.network_health_percentage = 100;
// Put the YBI into the table
MDB_val_set(key, m_height);
MDB_val_set(ybi_val, ybi);
result = mdb_cursor_put(m_cur_yield_blocks, &key, &ybi_val, MDB_APPEND);
if (result)
@@ -1004,6 +1096,7 @@ void BlockchainLMDB::remove_block()
CURSOR(blocks)
CURSOR(circ_supply_tally)
CURSOR(yield_blocks)
CURSOR(audit_blocks)
MDB_val_copy<uint64_t> k(m_height - 1);
MDB_val h = k;
if ((result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &h, MDB_GET_BOTH)))
@@ -1031,6 +1124,11 @@ void BlockchainLMDB::remove_block()
throw1(BLOCK_DNE(lmdb_error("Attempting to remove yield block info that's not in the db: ", result).c_str()));
if ((result = mdb_cursor_del(m_cur_yield_blocks, 0)))
throw1(DB_ERROR(lmdb_error("Failed to add removal of yield block info to db transaction: ", result).c_str()));
// Is the block within an audit window?
if ((result = mdb_cursor_get(m_cur_audit_blocks, &k2, NULL, MDB_SET)) == 0)
if ((result = mdb_cursor_del(m_cur_audit_blocks, 0)))
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit block info to db transaction: ", result).c_str()));
}
boost::multiprecision::int128_t
@@ -1116,6 +1214,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
CURSOR(circ_supply)
CURSOR(circ_supply_tally)
CURSOR(yield_txs)
CURSOR(audit_txs)
MDB_val_set(val_tx_id, tx_id);
MDB_val_set(val_h, tx_hash);
@@ -1183,13 +1282,19 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
throw0(DB_ERROR(lmdb_error("Failed to add prunable tx prunable hash to db transaction: ", result).c_str()));
}
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
if (tx.type == cryptonote::transaction_type::MINER) {
// Update the circulating supply tally because of potentially burnt block_reward proportion
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
std::string miner_asset_type = "SAL";
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
miner_asset_type = "SAL1";
}
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result && (m_height>0 || result != MDB_NOTFOUND))
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
boost::multiprecision::int128_t final_source_tally = source_tally;
for (const auto& out: tx.vout) {
@@ -1203,20 +1308,44 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
}
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
// Sanity check - prevent overflow
if (burn_tally > burn_tally + tx.amount_burnt)
throw0(DB_ERROR("burn overflow detected when adding miner_tx for db transaction"));
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt;
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
// Get the current tally value for the source currency type
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
boost::multiprecision::int128_t final_source_tally = source_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
// Sanity check - prevent underflow
if (source_tally < final_source_tally)
throw0(DB_ERROR("numeric underflow detected when processing C/B/S/A/T for db transaction"));
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
boost::multiprecision::int128_t final_burn_tally = burn_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
// Sanity check - prevent underflow
if (burn_tally > final_burn_tally)
throw0(DB_ERROR("burn overflow detected when adding tx for db transaction"));
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
@@ -1240,17 +1369,25 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
MDB_val_copy<uint64_t> source_idx(asset.first);
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result)
if (result == MDB_NOTFOUND)
throw0(DB_ERROR("minted asset not found"));
else if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
if (source_tally > source_tally + asset.second)
throw0(DB_ERROR("add_transaction_data() - mint overflow"));
boost::multiprecision::int128_t final_source_tally = source_tally + asset.second;
boost::multiprecision::int128_t coinbase = get_block_already_generated_coins(m_height-1);
if (source_tally == 0 && result == MDB_NOTFOUND) {
if (tx.source_asset_type == "SAL") {
final_source_tally += coinbase;
}
}
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before burn =" << source_tally.str() << "\n\tTally after burn =" << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
if (burn_tally < asset.second)
throw0(DB_ERROR("add_transaction_data() - burn underflow"));
boost::multiprecision::int128_t final_burn_tally = burn_tally - asset.second;
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
}
@@ -1261,7 +1398,17 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
yield_tx_info yield_data;
yield_data.block_height = m_height;
yield_data.tx_hash = tx_hash;
yield_data.return_address = tx.return_address;
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
if (tx.return_address == crypto::null_pkey)
throw0(DB_ERROR("missing return_address entry (needed to create yield data for PROTOCOL_TX) - v2 STAKE"));
yield_data.return_address = tx.return_address;
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
if (tx.return_address_list.empty())
throw0(DB_ERROR("no return_address_list entry (needed to create yield data for the PROTOCOL_TX)"));
else if (tx.return_address_list.size() > 1)
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create yield data for the PROTOCOL_TX)"));
yield_data.return_address = tx.return_address_list[0];
}
yield_data.locked_coins = tx.amount_burnt;
if (tx.vin.empty())
throw0(DB_ERROR("tx.vin is empty (needed to create yield data for the PROTOCOL_TX)"));
@@ -1298,6 +1445,60 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
throw0(DB_ERROR( lmdb_error("Failed to add tx yield data to db transaction: ", result).c_str() ));
}
// Is there audit_tx data to add?
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Create the object we are going to write to the database
yield_tx_info audit_data;
audit_data.block_height = m_height;
audit_data.tx_hash = tx_hash;
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
if (tx.return_address == crypto::null_pkey)
throw0(DB_ERROR("missing return_address entry (needed to create audit data for PROTOCOL_TX) - v2 STAKE"));
audit_data.return_address = tx.return_address;
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
if (tx.return_address_list.empty())
throw0(DB_ERROR("no return_address_list entry (needed to create audit data for the PROTOCOL_TX)"));
else if (tx.return_address_list.size() > 1)
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create audit data for the PROTOCOL_TX)"));
audit_data.return_address = tx.return_address_list[0];
}
audit_data.locked_coins = tx.amount_burnt;
if (tx.vin.empty())
throw0(DB_ERROR("tx.vin is empty (needed to create audit data for the PROTOCOL_TX)"));
if (tx.vin[0].type() != typeid(cryptonote::txin_to_key))
throw0(DB_ERROR("tx.vin[0] is wrong type (needed to create audit data for the PROTOCOL_TX)"));
audit_data.return_pubkey = tx.return_pubkey;
if (tx.vout.size() != 1)
throw0(DB_ERROR("tx.vout is wrong size (needed to create audit data for the PROTOCOL_TX)"));
if (!cryptonote::get_output_public_key(tx.vout[0], audit_data.P_change))
throw0(DB_ERROR("failed to get P_change from tx.vout[0] (needed to create audit data for the PROTOCOL_TX)"));
// Because LMDB is shockingly bad at handling duplicates, we have resorted to using a counter of elements
// in the first element of the struct.
MDB_val data;
MDB_val_set(val_height, m_height);
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &data, MDB_SET);
if (!result)
{
mdb_size_t num_elems = 0;
result = mdb_cursor_count(m_cur_audit_txs, &num_elems);
if (result)
throw0(DB_ERROR(std::string("Failed to get number of audit TXs for height: ").append(mdb_strerror(result)).c_str()));
audit_data.block_height = num_elems;
}
else if (result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str()));
else
audit_data.block_height = 0;
// Now we know how many there are, write out the data to the DB
MDB_val_set(val_audit_tx_data, audit_data);
result = mdb_cursor_put(m_cur_audit_txs, &val_height, &val_audit_tx_data, MDB_APPENDDUP);
if (result)
throw0(DB_ERROR( lmdb_error("Failed to add tx audit data to db transaction: ", result).c_str() ));
}
return tx_id;
}
@@ -1320,6 +1521,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
CURSOR(tx_outputs)
CURSOR(circ_supply_tally)
CURSOR(yield_txs)
CURSOR(audit_txs)
MDB_val_set(val_h, tx_hash);
@@ -1363,42 +1565,70 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
throw1(DB_ERROR(lmdb_error("Failed to add removal of prunable hash tx to db transaction: ", result).c_str()));
}
const uint8_t hf_version = m_hardfork->get_ideal_version(m_height);
if (tx.type == cryptonote::transaction_type::MINER) {
// Update the circulating supply tally because of potentially burnt block_reward proportion
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type("SAL"));
std::string miner_asset_type = "SAL";
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
miner_asset_type = "SAL1";
}
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(miner_asset_type));
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result && (m_height>0 || result != MDB_NOTFOUND))
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("remove_transaction_data() - Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
boost::multiprecision::int128_t final_source_tally = source_tally;
for (const auto& out: tx.vout) {
// Sanity check - prevent underflow
if (final_source_tally < final_source_tally - out.amount)
throw0(DB_ERROR("remove_transaction_data() - numeric underflow detected when removing miner_tx for db transaction"));
throw0(DB_ERROR("numeric underflow detected when removing miner_tx for db transaction"));
// Fetch the amount for this output
final_source_tally -= out.amount;
}
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before burn = " << source_tally.str() << "\n\tTally after burn = " << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && result != MDB_NOTFOUND)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
// Sanity check - prevent underflow
if (burn_tally < tx.amount_burnt)
throw0(DB_ERROR("burn underflow detected when removing miner_tx for db transaction"));
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt;
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE) {
if (tx.type == cryptonote::transaction_type::BURN || tx.type == cryptonote::transaction_type::CONVERT || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::TRANSFER) {
// Get the current tally value for the source currency type
MDB_val_copy<uint64_t> source_idx(cryptonote::asset_id_from_type(tx.source_asset_type));
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result == MDB_NOTFOUND)
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
// Sanity check - prevent overflow
if (source_tally > source_tally + tx.amount_burnt + tx.rct_signatures.txnFee)
throw0(DB_ERROR("remove_transaction_data() - numeric overflow detected when processing C/B/S for db transaction"));
boost::multiprecision::int128_t final_source_tally = source_tally + tx.amount_burnt + tx.rct_signatures.txnFee;
if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
// Sanity check - prevent overflow
if (source_tally > final_source_tally)
throw0(DB_ERROR("numeric overflow detected when processing C/B/S/A/T for db transaction"));
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tTally before remint =" << source_tally.str() << "\n\tTally after remint =" << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result && /*(m_height>0 ||*/ result != MDB_NOTFOUND/*)*/)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when adding db transaction: ", result).c_str()));
boost::multiprecision::int128_t final_burn_tally = burn_tally - tx.amount_burnt - tx.rct_signatures.txnFee;
// Sanity check - prevent underflow
if (burn_tally < (tx.amount_burnt + tx.rct_signatures.txnFee))
throw0(DB_ERROR("burn underflow detected when removing tx for db transaction"));
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
if (tx.type == cryptonote::transaction_type::PROTOCOL) {
@@ -1412,7 +1642,6 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
bool ok = cryptonote::get_output_asset_type(out, asset_type);
if (!ok)
throw0(DB_ERROR("failed to get output asset type (needed to update the circulating supply data for the PROTOCOL_TX)"));
minted_amounts[cryptonote::asset_id_from_type(asset_type)] += out.amount;
}
@@ -1424,12 +1653,24 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
boost::multiprecision::int128_t source_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, source_idx, source_tally);
if (result == MDB_NOTFOUND)
throw0(DB_ERROR("remove_transaction_data() - minted asset not found"));
throw0(DB_ERROR("minted asset not found"));
else if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
if (source_tally < asset.second)
throw0(DB_ERROR("remove_transaction_data() - mint underflow"));
boost::multiprecision::int128_t final_source_tally = source_tally - asset.second;
write_circulating_supply_data(m_cur_circ_supply_tally, source_idx, final_source_tally);
LOG_PRINT_L1("tx ID " << tip->data.tx_id << "\n\tAsset Type = " << cryptonote::asset_type_from_id(asset.first) << "\n\tTally before undoing mint =" << source_tally.str() << "\n\tTally after undoing mint =" << final_source_tally.str());
MDB_val_copy<uint64_t> burn_idx(cryptonote::asset_id_from_type("BURN"));
boost::multiprecision::int128_t burn_tally = 0;
result = read_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, burn_tally);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to get circulating supply tally when removing db transaction: ", result).c_str()));
if (burn_tally > burn_tally + asset.second)
throw0(DB_ERROR("remove_transaction_data() - burn overflow"));
boost::multiprecision::int128_t final_burn_tally = burn_tally + asset.second;
write_circulating_supply_data(m_cur_circ_supply_tally, burn_idx, final_burn_tally);
}
}
remove_tx_outputs(tip->data.tx_id, tx);
@@ -1446,7 +1687,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str()));
}
// SRCG: The following code is designed to clean up the STAKE transactions, but it is very poorly written
// SRCG: The following code is designed to clean up AUDIT+STAKE transactions, but it is very poorly written
// Since transactions are ALWAYS supposed to be created in order, it stands that they should ALWAYS be
// removed in REVERSE ORDER. Yet the following loop starts from the beginning - this is the worst possible
// implementation in performance terms, since it will ALWAYS take the longest possible time to remove the
@@ -1454,6 +1695,30 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const
// RECODE TO START FROM THE END OF THE DATABASE TABLE, AND THROW AN EXCEPTION IF YOU DO NOT MATCH FIRST TIME!
// Is there audit_tx data to remove?
if (tx.type == cryptonote::transaction_type::AUDIT) {
// Remove any yield_tx data for this transaction
MDB_val_set(val_height, m_height);
MDB_val v;
MDB_cursor_op op = MDB_SET;
while (1) {
result = mdb_cursor_get(m_cur_audit_txs, &val_height, &v, op);
if (result == MDB_NOTFOUND) {
throw1(DB_ERROR("Failed to locate audit tx for removal from db transaction"));
} else if (result) {
throw1(DB_ERROR(lmdb_error("Failed to locate audit_tx data for removal: ", result).c_str()));
}
op = MDB_NEXT_DUP;
const yield_tx_info ati = *(const yield_tx_info*)v.mv_data;
if (ati.tx_hash == tx_hash) {
result = mdb_cursor_del(m_cur_audit_txs, 0);
if (result)
throw1(DB_ERROR(lmdb_error("Failed to add removal of audit_tx data to db transaction: ", result).c_str()));
break;
}
}
}
// Is there yield_tx data to remove?
if (tx.type == cryptonote::transaction_type::STAKE) {
// Remove any yield_tx data for this transaction
@@ -1822,6 +2087,54 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB()
m_hardfork = nullptr;
}
#ifdef WIN32
static bool disable_ntfs_compression(const boost::filesystem::path& filepath)
{
DWORD file_attributes = ::GetFileAttributesW(filepath.c_str());
if (file_attributes == INVALID_FILE_ATTRIBUTES)
{
MERROR("Failed to get " << filepath.string() << " file attributes. Error: " << ::GetLastError());
return false;
}
if (!(file_attributes & FILE_ATTRIBUTE_COMPRESSED))
return true; // not compressed
LOG_PRINT_L1("Disabling NTFS compression for " << filepath.string());
HANDLE file_handle = ::CreateFileW(
filepath.c_str(),
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr,
OPEN_EXISTING,
boost::filesystem::is_directory(filepath) ? FILE_FLAG_BACKUP_SEMANTICS : 0, // Needed to open handles to directories
nullptr
);
if (file_handle == INVALID_HANDLE_VALUE)
{
MERROR("Failed to open handle: " << filepath.string() << ". Error: " << ::GetLastError());
return false;
}
USHORT compression_state = COMPRESSION_FORMAT_NONE;
DWORD bytes_returned;
BOOL ok = ::DeviceIoControl(
file_handle,
FSCTL_SET_COMPRESSION,
&compression_state,
sizeof(compression_state),
nullptr,
0,
&bytes_returned,
nullptr
);
::CloseHandle(file_handle);
return ok;
}
#endif
void BlockchainLMDB::open(const std::string& filename, const int db_flags)
{
int result;
@@ -1848,6 +2161,18 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
throw DB_ERROR("Database could not be opened");
}
#ifdef WIN32
// ensure NTFS compression is disabled on the directory and database file to avoid corruption of the blockchain
if (!disable_ntfs_compression(filename))
LOG_PRINT_L0("Failed to disable NTFS compression on folder: " << filename << ". Error: " << ::GetLastError());
boost::filesystem::path datafile(filename);
datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
if (!boost::filesystem::exists(datafile))
boost::filesystem::ofstream(datafile).close(); // create the file to see if NTFS compression is enabled beforehand
if (!disable_ntfs_compression(datafile))
throw DB_ERROR("Database file is NTFS compressed and compression could not be disabled");
#endif
boost::optional<bool> is_hdd_result = tools::is_hdd(filename.c_str());
if (is_hdd_result)
{
@@ -1960,6 +2285,9 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
lmdb_db_open(txn, LMDB_YIELD_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_yield_txs, "Failed to open db handle for m_yield_txs");
lmdb_db_open(txn, LMDB_YIELD_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_yield_blocks, "Failed to open db handle for m_yield_blocks");
lmdb_db_open(txn, LMDB_AUDIT_TXS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_audit_txs, "Failed to open db handle for m_audit_txs");
lmdb_db_open(txn, LMDB_AUDIT_BLOCKS, MDB_INTEGERKEY | MDB_CREATE, m_audit_blocks, "Failed to open db handle for m_audit_blocks");
mdb_set_dupsort(txn, m_spent_keys, compare_hash32);
mdb_set_dupsort(txn, m_block_heights, compare_hash32);
mdb_set_dupsort(txn, m_tx_indices, compare_hash32);
@@ -1983,6 +2311,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
mdb_set_compare(txn, m_circ_supply_tally, compare_uint64);
mdb_set_dupsort(txn, m_yield_txs, compare_uint64);
mdb_set_dupsort(txn, m_audit_txs, compare_uint64);
if (!(mdb_flags & MDB_RDONLY))
{
@@ -2164,6 +2493,10 @@ void BlockchainLMDB::reset()
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_txs: ", result).c_str()));
if (auto result = mdb_drop(txn, m_yield_blocks, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_yield_blocks: ", result).c_str()));
if (auto result = mdb_drop(txn, m_audit_txs, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_txs: ", result).c_str()));
if (auto result = mdb_drop(txn, m_audit_blocks, 0))
throw0(DB_ERROR(lmdb_error("Failed to drop m_audit_blocks: ", result).c_str()));
// init with current version
MDB_val_str(k, "version");
@@ -3506,9 +3839,14 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
// Check for SAL - we need to adjust the total for them
if (currency_type == 0) {
// Get the current circulating supply for SAL
amount += m_coinbase;
//amount += m_coinbase;
}
if (amount < 0) {
// Negative number can't be converted to a 64-bit UINT, so return 0, but retain -ve number privately
LOG_PRINT_L2("BlockchainLMDB::" << __func__ << " - supply of " << currency_label << " is negative (" << amount << ") but outputting zero");
amount = 0;
}
circulating_supply[currency_label] = amount.convert_to<uint64_t>();
}
@@ -3517,12 +3855,13 @@ std::map<std::string,uint64_t> BlockchainLMDB::get_circulating_supply() const
// NEAC: check for empty supply tally - only happens prior to first conversion on chain
if (circulating_supply.empty()) {
circulating_supply["SAL"] = m_coinbase;
circulating_supply["SAL1"] = 0;
circulating_supply["BURN"] = 0;
}
// Adjust the supply to account for the staked coins
circulating_supply["STAKE"] = staked_coins;
circulating_supply["BURN"] = m_coinbase - circulating_supply["SAL"] - circulating_supply["STAKE"];
return circulating_supply;
}
@@ -4714,7 +5053,7 @@ void BlockchainLMDB::block_rtxn_abort() const
}
uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t block_weight, uint64_t long_term_block_weight, 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 std::vector<std::pair<transaction, blobdata>>& txs, const cryptonote::network_type nettype, cryptonote::yield_block_info& ybi, cryptonote::audit_block_info& abi)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
@@ -4732,7 +5071,7 @@ uint64_t BlockchainLMDB::add_block(const std::pair<block, blobdata>& blk, size_t
try
{
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi);
BlockchainDB::add_block(blk, block_weight, long_term_block_weight, cumulative_difficulty, coins_generated, txs, nettype, ybi, abi);
}
catch (const DB_ERROR_TXN_START& e)
{
@@ -5197,12 +5536,11 @@ bool BlockchainLMDB::is_read_only() const
uint64_t BlockchainLMDB::get_database_size() const
{
uint64_t size = 0;
boost::filesystem::path datafile(m_folder);
datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME;
if (!epee::file_io_utils::get_file_size(datafile.string(), size))
size = 0;
return size;
boost::system::error_code ec{};
const boost::uintmax_t size = boost::filesystem::file_size(datafile, ec);
return (ec ? 0 : static_cast<uint64_t>(size));
}
#define RENAME_DB(name) do { \
@@ -5229,8 +5567,38 @@ uint64_t BlockchainLMDB::get_database_size() const
#define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global"))
void BlockchainLMDB::migrate_2_3()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
uint64_t i;
int result;
mdb_txn_safe txn(false);
MDB_val k, v;
char *ptr;
MGINFO_YELLOW("Migrating blockchain from DB version 2 to 3 - this may take a while:");
// Create the missing (and empty) "audit_block_info" records for all blocks
do {
} while(0);
uint32_t version = VERSION;
v.mv_data = (void *)&version;
v.mv_size = sizeof(version);
MDB_val_str(vk, "version");
result = mdb_txn_begin(m_env, NULL, 0, txn);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str()));
result = mdb_put(txn, m_properties, &vk, &v, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Failed to update version for the db: ", result).c_str()));
txn.commit();
}
void BlockchainLMDB::migrate(const uint32_t oldversion)
{
//if (oldversion < 3)
// migrate_2_3();
}
} // namespace cryptonote
+21 -5
View File
@@ -78,6 +78,8 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_circ_supply_tally;
MDB_cursor *m_txc_yield_txs;
MDB_cursor *m_txc_yield_blocks;
MDB_cursor *m_txc_audit_txs;
MDB_cursor *m_txc_audit_blocks;
} mdb_txn_cursors;
@@ -104,6 +106,8 @@ typedef struct mdb_txn_cursors
#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
#define m_cur_audit_txs m_cursors->m_txc_audit_txs
#define m_cur_audit_blocks m_cursors->m_txc_audit_blocks
typedef struct mdb_rflags
{
@@ -131,6 +135,8 @@ typedef struct mdb_rflags
bool m_rf_circ_supply_tally;
bool m_rf_yield_txs;
bool m_rf_yield_blocks;
bool m_rf_audit_txs;
bool m_rf_audit_blocks;
} mdb_rflags;
typedef struct mdb_threadinfo
@@ -341,8 +347,9 @@ public:
, const difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, const std::vector<std::pair<transaction, blobdata>>& txs
, const cryptonote::network_type& nettype
, const cryptonote::network_type nettype
, cryptonote::yield_block_info& ybi
, cryptonote::audit_block_info& abi
);
virtual void set_batch_transactions(bool batch_transactions);
@@ -400,8 +407,10 @@ private:
const crypto::hash& blk_hash,
uint64_t slippage_total,
uint64_t yield_total,
const cryptonote::network_type& nettype,
cryptonote::yield_block_info& ybi
uint64_t audit_total,
const cryptonote::network_type nettype,
cryptonote::yield_block_info& ybi,
cryptonote::audit_block_info& abi
);
virtual void remove_block();
@@ -455,10 +464,14 @@ private:
// 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 2 to 3
void migrate_2_3();
void cleanup_batch();
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const;
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const;
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const;
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const;
@@ -499,6 +512,9 @@ private:
MDB_dbi m_yield_txs;
MDB_dbi m_yield_blocks;
MDB_dbi m_audit_txs;
MDB_dbi m_audit_blocks;
mutable uint64_t m_cum_size; // used in batch size estimation
mutable unsigned int m_cum_count;
std::string m_folder;
+32 -14
View File
@@ -76,7 +76,7 @@ public:
virtual uint64_t get_block_height(const crypto::hash& h) const override { return 0; }
virtual cryptonote::block_header get_block_header(const crypto::hash& h) const override { return cryptonote::block_header(); }
virtual uint64_t get_block_timestamp(const uint64_t& height) const override { return 0; }
virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const override { return {}; }
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 override { return {}; }
virtual uint64_t get_top_block_timestamp() const override { return 0; }
virtual size_t get_block_weight(const uint64_t& height) const override { return 128; }
virtual std::vector<uint64_t> get_block_weights(uint64_t start_height, size_t count) const override { return {}; }
@@ -92,6 +92,7 @@ public:
virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const override { if (block_height) *block_height = 0; return crypto::hash(); }
virtual cryptonote::block get_top_block() const override { return cryptonote::block(); }
virtual uint64_t height() const override { return 1; }
virtual std::map<std::string, uint64_t> get_circulating_supply() const override { return std::map<std::string, uint64_t>{}; }
virtual bool tx_exists(const crypto::hash& h) const override { return false; }
virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const override { return false; }
virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const override { return 0; }
@@ -101,20 +102,23 @@ public:
virtual std::vector<cryptonote::transaction> get_tx_list(const std::vector<crypto::hash>& hlist) const override { return std::vector<cryptonote::transaction>(); }
virtual uint64_t get_tx_block_height(const crypto::hash& h) const override { return 0; }
virtual uint64_t get_num_outputs(const uint64_t& amount) const override { return 1; }
virtual uint64_t get_num_outputs_of_asset_type(const std::string asset_type) const override { return 1; }
virtual uint64_t get_indexing_base() const override { return 0; }
virtual cryptonote::output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, bool include_commitmemt) const override { return cryptonote::output_data_t(); }
virtual cryptonote::tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const override { return cryptonote::tx_out_index(); }
virtual cryptonote::tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const override { return cryptonote::tx_out_index(); }
virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector<uint64_t> &offsets, std::vector<cryptonote::tx_out_index> &indices) const override {}
virtual void get_output_key(const epee::span<const uint64_t> &amounts, const std::vector<uint64_t> &offsets, std::vector<cryptonote::output_data_t> &outputs, bool allow_partial = false) const override {}
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 override {}
virtual uint64_t get_output_id_from_asset_type_output_index(const std::string asset_type, const uint64_t &asset_type_output_index) const override { return 1; }
virtual bool can_thread_bulk_indices() const override { return false; }
virtual std::vector<std::vector<uint64_t>> get_tx_amount_output_indices(const uint64_t tx_index, size_t n_txes) const override { return std::vector<std::vector<uint64_t>>(); }
virtual std::vector<std::vector<std::pair<uint64_t, uint64_t>>> get_tx_amount_output_indices(const uint64_t tx_index, size_t n_txes) const override { return std::vector<std::vector<std::pair<uint64_t, uint64_t>>>(); }
virtual bool has_key_image(const crypto::key_image& img) const override { return false; }
virtual void remove_block() override { }
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<cryptonote::transaction, cryptonote::blobdata_ref>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash) override {return 0;}
virtual void remove_transaction_data(const crypto::hash& tx_hash, const cryptonote::transaction& tx) override {}
virtual uint64_t add_output(const crypto::hash& tx_hash, const cryptonote::tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) override {return 0;}
virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<uint64_t>& amount_output_indices) override {}
virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const std::pair<cryptonote::transaction, cryptonote::blobdata_ref>& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prunable_hash, const bool miner_tx) override {return 0;}
virtual void remove_transaction_data(const crypto::hash& tx_hash, const cryptonote::transaction& tx, const bool miner_tx) override {}
virtual std::pair<uint64_t, uint64_t> add_output(const crypto::hash& tx_hash, const cryptonote::tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) override {return std::make_pair(0,0);}
virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector<std::pair<uint64_t, uint64_t>>& amount_output_indices) override {}
virtual void add_spent_key(const crypto::key_image& k_image) override {}
virtual void remove_spent_key(const crypto::key_image& k_image) override {}
@@ -135,17 +139,31 @@ public:
virtual bool get_txpool_tx_meta(const crypto::hash& txid, cryptonote::txpool_tx_meta_t &meta) const override { return false; }
virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd, relay_category tx_category) const override { return false; }
virtual uint64_t get_database_size() const override { return 0; }
virtual int get_audit_block_info(const uint64_t height, audit_block_info& abi) const override { return 0; }
virtual int get_audit_tx_info(const uint64_t height, std::vector<yield_tx_info>& ati_container) const override { return 0; }
virtual int get_yield_block_info(const uint64_t height, yield_block_info& ybi) const override { return 0; }
virtual int get_yield_tx_info(const uint64_t height, std::vector<yield_tx_info>& yti_container) const override { return 0; }
virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid, relay_category tx_category) const override { return ""; }
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const cryptonote::txpool_tx_meta_t&, const cryptonote::blobdata_ref*)>, bool include_blob = false, relay_category category = relay_category::broadcasted) const override { return false; }
virtual void add_block( const cryptonote::block& blk
, size_t block_weight
, uint64_t long_term_block_weight
, const cryptonote::difficulty_type& cumulative_difficulty
, const uint64_t& coins_generated
, uint64_t num_rct_outs
, const crypto::hash& blk_hash
) override { }
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,
uint64_t audit_total,
const cryptonote::network_type nettype,
cryptonote::yield_block_info& ybi,
cryptonote::audit_block_info& abi
) override { }
virtual cryptonote::block get_block_from_height(const uint64_t& height) const override { return cryptonote::block(); }
virtual void set_hard_fork_version(uint64_t height, uint8_t version) override {}
virtual uint8_t get_hard_fork_version(uint64_t height) const override { return 0; }
+75
View File
@@ -133,6 +133,31 @@ monero_private_headers(blockchain_stats
${blockchain_stats_private_headers})
set(blockchain_scanner_sources
blockchain_scanner.cpp
)
set(blockchain_scanner_private_headers)
monero_private_headers(blockchain_scanner
${blockchain_scanner_private_headers})
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
set(blockchain_audit_sources
blockchain_audit.cpp
threadpool_boost.cpp
)
set(blockchain_audit_private_headers
threadpool_boost.h
)
monero_private_headers(blockchain_audit
${blockchain_audit_private_headers})
else()
message(STATUS "blockchain_audit.cpp not found - not building the audit tool")
endif()
monero_add_executable(blockchain_import
${blockchain_import_sources}
${blockchain_import_private_headers})
@@ -281,6 +306,56 @@ set_property(TARGET blockchain_depth
OUTPUT_NAME "salvium-blockchain-depth")
install(TARGETS blockchain_depth DESTINATION bin)
monero_add_executable(blockchain_scanner
${blockchain_scanner_sources}
${blockchain_scanner_private_headers})
target_link_libraries(blockchain_scanner
PRIVATE
cryptonote_core
blockchain_db
version
epee
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
set_property(TARGET blockchain_scanner
PROPERTY
OUTPUT_NAME "salvium-blockchain-scanner")
install(TARGETS blockchain_scanner DESTINATION bin)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp" AND NOT IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/blockchain_audit.cpp")
monero_add_executable(blockchain_audit
${blockchain_audit_sources}
${blockchain_audit_private_headers})
target_include_directories(blockchain_audit PRIVATE /usr/include/mysql-cppconn/jdbc)
target_link_libraries(blockchain_audit
PRIVATE
wallet
crypto
cncrypto
cryptonote_core
blockchain_db
version
epee
mysqlcppconn
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
set_property(TARGET blockchain_audit
PROPERTY
OUTPUT_NAME "salvium-blockchain-audit")
install(TARGETS blockchain_audit DESTINATION bin)
endif()
monero_add_executable(blockchain_stats
${blockchain_stats_sources}
${blockchain_stats_private_headers})
@@ -488,8 +488,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
cryptonote::audit_block_info abi; // This just gets discarded because we aren't looking to maintain a cache of ABI 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, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, ybi);
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, abi);
}
catch (const std::exception& e)
{
@@ -0,0 +1,386 @@
// Copyright (c) 2014-2019, 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 <boost/algorithm/string.hpp>
#include <boost/filesystem.hpp>
#include "common/command_line.h"
#include "common/i18n.h"
#include "common/password.h"
#include "common/varint.h"
#include "cryptonote_basic/cryptonote_boost_serialization.h"
#include "cryptonote_core/tx_pool.h"
#include "cryptonote_core/cryptonote_core.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "cryptonote_core/blockchain.h"
#include "blockchain_db/blockchain_db.h"
#include "oracle/pricing_record.h"
#include "version.h"
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "bcutil"
#define DELIM "|"
#define DEF_STAKE_MODE "all"
namespace po = boost::program_options;
using namespace epee;
using namespace cryptonote;
namespace scanner
{
const char* tr(const char* str)
{
return i18n_translate(str, "tools::scanner");
}
}
static bool stop_requested = false;
int main(int argc, char* argv[])
{
TRY_ENTRY();
epee::string_tools::set_module_name_and_folder(argv[0]);
uint32_t log_level = 0;
uint64_t block_start = 0;
uint64_t block_stop = 0;
tools::on_startup();
boost::filesystem::path output_file_path;
po::options_description desc_cmd_only("Command line options");
po::options_description desc_cmd_sett("Command line options and settings options");
const command_line::arg_descriptor<std::string> arg_log_level = {"log-level", "0-4 or categories", ""};
const command_line::arg_descriptor<uint64_t> arg_block_start = {"block-start", "start at block number", block_start};
const command_line::arg_descriptor<uint64_t> arg_block_stop = {"block-stop", "Stop at block number", block_stop};
const command_line::arg_descriptor<std::string> arg_delimiter = {"delimiter", "\"<string>\"", DELIM};
const command_line::arg_descriptor<std::string> arg_stake_mode = {"stake", "\"<string>\"", DEF_STAKE_MODE};
const command_line::arg_descriptor<bool> arg_check_asset_types = {"check-asset-types", "Scan for asset-type issues", false};
command_line::add_arg(desc_cmd_sett, cryptonote::arg_data_dir);
command_line::add_arg(desc_cmd_sett, cryptonote::arg_testnet_on);
command_line::add_arg(desc_cmd_sett, cryptonote::arg_stagenet_on);
command_line::add_arg(desc_cmd_sett, arg_log_level);
command_line::add_arg(desc_cmd_sett, arg_block_start);
command_line::add_arg(desc_cmd_sett, arg_block_stop);
command_line::add_arg(desc_cmd_sett, arg_delimiter);
command_line::add_arg(desc_cmd_sett, arg_stake_mode);
command_line::add_arg(desc_cmd_sett, arg_check_asset_types);
command_line::add_arg(desc_cmd_only, command_line::arg_help);
po::options_description desc_options("Allowed options");
desc_options.add(desc_cmd_only).add(desc_cmd_sett);
po::variables_map vm;
bool r = command_line::handle_error_helper(desc_options, [&]()
{
auto parser = po::command_line_parser(argc, argv).options(desc_options);
po::store(parser.run(), vm);
po::notify(vm);
return true;
});
if (! r)
return 1;
if (command_line::get_arg(vm, command_line::arg_help))
{
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);
if (!command_line::is_arg_defaulted(vm, arg_log_level))
mlog_set_log(command_line::get_arg(vm, arg_log_level).c_str());
else
mlog_set_log(std::string(std::to_string(log_level) + ",bcutil:INFO").c_str());
LOG_PRINT_L0("Starting...");
std::string opt_data_dir = command_line::get_arg(vm, cryptonote::arg_data_dir);
bool opt_testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on);
bool opt_stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on);
network_type net_type = opt_testnet ? TESTNET : opt_stagenet ? STAGENET : MAINNET;
block_start = command_line::get_arg(vm, arg_block_start);
block_stop = command_line::get_arg(vm, arg_block_stop);
std::string delimiter = command_line::get_arg(vm, arg_delimiter);
std::string stake_mode = command_line::get_arg(vm, arg_stake_mode);
bool opt_check_asset_types = command_line::get_arg(vm, arg_check_asset_types);
// If we wanted to use the memory pool, we would set up a fake_core.
// Use Blockchain instead of lower-level BlockchainDB for two reasons:
// 1. Blockchain has the init() method for easy setup
// 2. exporter needs to use get_current_blockchain_height(), get_block_id_by_height(), get_block_by_hash()
//
// cannot match blockchain_storage setup above with just one line,
// e.g.
// Blockchain* core_storage = new Blockchain(NULL);
// because unlike blockchain_storage constructor, which takes a pointer to
// tx_memory_pool, Blockchain's constructor takes tx_memory_pool object.
LOG_PRINT_L0("Initializing source blockchain (BlockchainDB)");
std::unique_ptr<BlockchainAndPool> core_storage = std::make_unique<BlockchainAndPool>();
BlockchainDB* db = new_db();
if (db == NULL)
{
LOG_ERROR("Failed to initialize a database");
throw std::runtime_error("Failed to initialize a database");
}
LOG_PRINT_L0("database: LMDB");
boost::filesystem::path folder(opt_data_dir);
if (opt_stagenet) {
folder /= std::to_string(STAGENET_VERSION);
} else if (opt_testnet) {
folder /= std::to_string(TESTNET_VERSION);
}
folder /= db->get_db_name();
LOG_PRINT_L0("Loading blockchain from folder " << folder << " ...");
const std::string filename = folder.string();
try
{
db->open(filename, DBF_RDONLY);
}
catch (const std::exception& e)
{
LOG_PRINT_L0("Error opening database: " << e.what());
return 1;
}
r = core_storage->blockchain.init(db, net_type);
CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage");
LOG_PRINT_L0("Source blockchain storage initialized OK");
tools::signal_handler::install([](int type) {
stop_requested = true;
});
const uint64_t db_height = db->height();
if (!block_stop)
block_stop = db_height;
MINFO("Starting from height " << block_start << ", stopping at height " << block_stop);
/*
* The default output can be plotted with GnuPlot using these commands:
set key autotitle columnhead
set title "Salvium Blockchain Growth"
set timefmt "%Y-%m-%d"
set xdata time
set xrange ["2014-04-17":*]
set format x "%Y-%m-%d"
set yrange [0:*]
set y2range [0:*]
set ylabel "Txs/Day"
set y2label "Bytes"
set y2tics nomirror
plot 'stats.csv' index "DATA" using (timecolumn(1,"%Y-%m-%d")):4 with lines, '' using (timecolumn(1,"%Y-%m-%d")):7 axes x1y2 with lines
*/
// spit out a comment that GnuPlot can use as an index
std::cout << ENDL << "# DATA" << ENDL;
std::cout << "Date" << delimiter << "Height" << delimiter << "Transaction ID" << delimiter << "Reason" << delimiter << "Extra Information";
std::cout << ENDL;
#define MAX_INOUT 0xffffffff
#define MAX_RINGS 0xffffffff
struct tm prevtm = {0}, currtm;
uint64_t prevsz = 0, currsz = 0;
uint64_t prevtxs = 0, currtxs = 0;
uint64_t currblks = 0;
uint32_t txhr[24] = {0};
unsigned int i;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> audit_hard_forks = get_config(net_type).AUDIT_HARD_FORKS;
for (uint64_t h = block_start; h < block_stop; ++h)
{
cryptonote::blobdata bd = db->get_block_blob_from_height(h);
cryptonote::block blk;
if (!cryptonote::parse_and_validate_block_from_blob(bd, blk))
{
LOG_PRINT_L0("Bad block from db");
return 1;
}
time_t tt = blk.timestamp;
char timebuf[64];
epee::misc_utils::get_gmt_time(tt, currtm);
if (!prevtm.tm_year)
prevtm = currtm;
// catch change of day
if (currtm.tm_mday > prevtm.tm_mday || (currtm.tm_mday == 1 && prevtm.tm_mday > 27))
{
// check for timestamp fudging around month ends
if (prevtm.tm_mday == 1 && currtm.tm_mday > 27)
goto skip;
strftime(timebuf, sizeof(timebuf), "%Y-%m-%d", &currtm);
prevtm = currtm;
}
skip:
currsz += bd.size();
uint64_t coinbase_amount;
uint64_t tx_fee_amount = 0;
std::set<std::string> used_assets, miner_tx_assets, protocol_tx_assets;
std::map<size_t, std::vector<std::string>> used_tx_versions;
used_assets.insert("SAL");
uint8_t hf_version = blk.major_version;
// Check TX versions
if (blk.miner_tx.version != 2) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX version detected" << delimiter << "version:" << blk.miner_tx.version << std::endl;
}
if (blk.protocol_tx.version != 2 && h>0) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX version detected" << delimiter << "version:" << blk.protocol_tx.version << std::endl;
}
// Get the miner_tx assets
std::set<crypto::public_key> used_keys;
for (const auto& miner_tx_vout : blk.miner_tx.vout) {
std::string asset_type;
if (!cryptonote::get_output_asset_type(miner_tx_vout, asset_type)) {
throw std::runtime_error("Aborting: failed to get output asset type from miner_tx");
} else if (blk.major_version >= HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL1") {
throw std::runtime_error("Aborting: invalid output asset type from miner_tx: " + asset_type);
} else if (blk.major_version < HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from miner_tx: " + asset_type + ", HF:" + std::to_string(blk.major_version));
}
miner_tx_assets.insert(asset_type);
if (miner_tx_vout.amount > 13500000000 && h>0) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX amount detected" << delimiter << "amount:" << miner_tx_vout.amount << std::endl;
}
crypto::public_key key;
cryptonote::get_output_public_key(miner_tx_vout, key);
if (used_keys.count(key)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.miner_tx.hash << "" << delimiter << "invalid miner TX - duplicate output detected" << delimiter << "pubkey:" << key << std::endl;
}
used_keys.insert(key);
}
// Get the protocol_tx assets
used_keys.clear();
for (const auto& protocol_tx_vout : blk.protocol_tx.vout) {
std::string asset_type;
if (!cryptonote::get_output_asset_type(protocol_tx_vout, asset_type)) {
throw std::runtime_error("Aborting: failed to get output asset type from protocol_tx");
} else if (blk.major_version >= HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL1") {
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx: " + asset_type);
} else if (blk.major_version < HF_VERSION_SALVIUM_ONE_PROOFS && asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from protocol_tx: " + asset_type + ", HF:" + std::to_string(blk.major_version));
}
protocol_tx_assets.insert(asset_type);
if (protocol_tx_vout.amount > 25000000000000) {
//std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "large protocol TX amount detected from height " << (h-audit_lock_period) << delimiter << "amount:" << protocol_tx_vout.amount << std::endl;
}
crypto::public_key key;
cryptonote::get_output_public_key(protocol_tx_vout, key);
if (used_keys.count(key)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << blk.protocol_tx.hash << "" << delimiter << "invalid protocol TX - duplicate output detected" << delimiter << "pubkey:" << key << std::endl;
}
used_keys.insert(key);
}
for (const auto& tx_id : blk.tx_hashes)
{
if (tx_id == crypto::null_hash)
{
throw std::runtime_error("Aborting: tx == null_hash");
}
if (!db->get_pruned_tx_blob(tx_id, bd))
{
throw std::runtime_error("Aborting: tx not found");
}
transaction tx;
if (!parse_and_validate_tx_base_from_blob(bd, tx))
{
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX detected" << delimiter << std::endl;
continue;
}
currsz += bd.size();
if (db->get_prunable_tx_blob(tx_id, bd))
currsz += bd.size();
currtxs++;
if (tx.type != cryptonote::transaction_type::TRANSFER &&
tx.type != cryptonote::transaction_type::BURN &&
tx.type != cryptonote::transaction_type::STAKE &&
tx.type != cryptonote::transaction_type::AUDIT) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX type detected" << delimiter << "type:" << (uint8_t)tx.type << std::endl;
}
if ((tx.version != 2 && hf_version < HF_VERSION_ENABLE_N_OUTS) || (tx.version != 3 && hf_version < HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER)) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "invalid TX version detected" << delimiter << "version:" << tx.version << std::endl;
}
if (tx.type == cryptonote::transaction_type::STAKE && stake_mode.compare("off")) {
if (stake_mode.compare("all") == 0) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "STAKE TX detected" << delimiter << "amount:" << (tx.amount_burnt / 100000000) << std::endl;
} else if (stake_mode.compare("large") == 0 && tx.amount_burnt > 25000000000000llu) {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "large STAKE TX detected" << delimiter << "amount:" << (tx.amount_burnt / 100000000) << std::endl;
}
}
if (opt_check_asset_types) {
if (tx.source_asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid source asset type found in tx");
} else if (tx.destination_asset_type != "SAL") {
if (tx.destination_asset_type == "BURN") {
std::cout << timebuf << "" << delimiter << "" << h << "" << delimiter << "" << tx_id << "" << delimiter << "BURN TX detected" << delimiter << "amount:" << tx.amount_burnt << std::endl;
} else {
throw std::runtime_error("Aborting: invalid destination asset type found in tx");
}
}
for (const auto& tx_vout : tx.vout) {
std::string asset_type;
if (!cryptonote::get_output_asset_type(tx_vout, asset_type)) {
throw std::runtime_error("Aborting: failed to get output asset type from tx");
} else if (asset_type != "SAL") {
throw std::runtime_error("Aborting: invalid output asset type from tx");
}
}
// Add the source currency to the list of expected ones
used_assets.insert(tx.source_asset_type);
}
}
currblks++;
if (stop_requested)
break;
}
return 0;
CATCH_ENTRY("Stats reporting error", 1);
}
@@ -0,0 +1,44 @@
#include <iostream>
#include "threadpool_boost.h"
ThreadPool::ThreadPool(size_t numThreads)
: workGuard(boost::asio::make_work_guard(ioService)) {
for (size_t i = 0; i < numThreads; ++i) {
workers.emplace_back([this]() {
std::cerr << "Thread started" << std::endl;
ioService.run();
std::cerr << "Thread finished" << std::endl;
});
}
}
void ThreadPool::enqueue(std::function<void()> task) {
ioService.post([task]() {
try {
task(); // Run the task
} catch (const std::exception& e) {
std::cerr << "Exception in thread pool task: " << e.what() << std::endl;
} catch (...) {
std::cerr << "Unknown exception in thread pool task!" << std::endl;
}
});
}
bool ThreadPool::isStopping() const {
return ioService.stopped(); // Check if io_context has stopped
}
void ThreadPool::waitForCompletion() {
std::cout << "Waiting for completion...\n";
workGuard.reset(); // Allow ioService to stop when no more tasks
ioService.run(); // Ensure no threads are left hanging
for (auto &worker : workers) {
if (worker.joinable()) worker.join();
}
std::cout << "All threads joined.\n";
}
ThreadPool::~ThreadPool() {
waitForCompletion();
}
@@ -0,0 +1,24 @@
#ifndef THREADPOOL_BOOST_H
#define THREADPOOL_BOOST_H
#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <functional>
#include <vector>
class ThreadPool {
public:
explicit ThreadPool(size_t numThreads);
~ThreadPool();
void enqueue(std::function<void()> task);
bool isStopping() const;
void waitForCompletion();
private:
boost::asio::io_service ioService;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> workGuard;
std::vector<boost::thread> workers;
};
#endif // THREADPOOL_BOOST_H
Binary file not shown.
+1
View File
@@ -204,6 +204,7 @@ namespace cryptonote
ADD_CHECKPOINT2(180, "e20bc8ac6aabb6b0792f23a29ce42a577c6a57d177a8ac1a51b68fb6de508045", "0x262b40");
ADD_CHECKPOINT2(190, "f69fdad7a15471b63a82668b618ee5b2a384291269d944b11974a723c1604124", "0x2856a3");
ADD_CHECKPOINT2(200, "eba53fa7006dfcdc837a56c0bc8f0e1883cf34861c26934d680252a6878a3f5d", "0x2aa022");
ADD_CHECKPOINT2(90000, "e125b5c1b26521f98e29df6ec88f041c176a2c0a3fcacd5bd0ad2278e9b02fd2", "0xc99801f937888"); // 3546475285149832
}
return true;
}
+5 -3
View File
@@ -30,7 +30,6 @@
#include <atomic>
#include <boost/filesystem.hpp>
#include <boost/thread/thread.hpp>
#include "file_io_utils.h"
#include "net/http_client.h"
#include "download.h"
@@ -73,8 +72,11 @@ namespace tools
{
boost::unique_lock<boost::mutex> lock(control->mutex);
std::ios_base::openmode mode = std::ios_base::out | std::ios_base::binary;
uint64_t existing_size = 0;
if (epee::file_io_utils::get_file_size(control->path, existing_size) && existing_size > 0)
boost::system::error_code ec{};
uint64_t existing_size = static_cast<uint64_t>(boost::filesystem::file_size(control->path, ec));
if (ec)
existing_size = 0;
if (existing_size > 0)
{
MINFO("Resuming downloading " << control->uri << " to " << control->path << " from " << existing_size);
mode |= std::ios_base::app;
+1 -1
View File
@@ -185,7 +185,7 @@ namespace
return false;
if (verify)
{
std::cout << "Confirm password: ";
std::cout << "Confirm password: " << std::flush;
if (!read_from_tty(pass2, hide_input))
return false;
if(pass1!=pass2)
+1
View File
@@ -34,6 +34,7 @@
#include "easylogging++/easylogging++.h"
#include <stdexcept>
#include <iomanip>
#ifdef USE_UNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
+1 -1
View File
@@ -664,7 +664,7 @@ namespace tools
}
boost::system::error_code ec;
const auto parsed_ip = boost::asio::ip::address::from_string(u_c.host, ec);
const auto parsed_ip = boost::asio::ip::make_address(u_c.host, ec);
if (ec) {
MDEBUG("Failed to parse '" << address << "' as IP address: " << ec.message() << ". Considering it not local");
return false;
+1 -1
View File
@@ -71,7 +71,7 @@ target_link_libraries(cncrypto
epee
randomx
${Boost_SYSTEM_LIBRARY}
${sodium_LIBRARIES}
${SODIUM_LIBRARY}
PRIVATE
${EXTRA_LIBRARIES})
+20 -4
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2022, The Monero Project
// Copyright (c) 2014-2024, The Monero Project
//
// All rights reserved.
//
@@ -171,7 +171,9 @@ namespace crypto {
/* Generate a value filled with random bytes.
*/
template<typename T>
typename std::enable_if<std::is_pod<T>::value, T>::type rand() {
T rand() {
static_assert(std::is_standard_layout<T>(), "cannot write random bytes into non-standard layout type");
static_assert(std::is_trivially_copyable<T>(), "cannot write random bytes into non-trivially copyable type");
typename std::remove_cv<T>::type res;
generate_random_bytes_thread_safe(sizeof(T), (uint8_t*)&res);
return res;
@@ -314,8 +316,14 @@ namespace crypto {
inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
}
inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
/* Do NOT overload the << operator for crypto::secret_key here. Use secret_key_explicit_print_ref
* instead to prevent accidental implicit dumping of secret key material to the logs (which has
* happened before). For the same reason, do not overload it for crypto::ec_scalar either since
* crypto::secret_key is a subclass. I'm not sorry that it's obtuse; that's the point, bozo.
*/
struct secret_key_explicit_print_ref { const crypto::secret_key &sk; };
inline std::ostream &operator <<(std::ostream &o, const secret_key_explicit_print_ref v) {
epee::to_hex::formatted(o, epee::as_byte_span(unwrap(unwrap(v.sk)))); return o;
}
inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
epee::to_hex::formatted(o, epee::as_byte_span(v)); return o;
@@ -335,8 +343,16 @@ namespace crypto {
inline bool operator<(const public_key &p1, const public_key &p2) { return memcmp(&p1, &p2, sizeof(public_key)) < 0; }
inline bool operator>(const public_key &p1, const public_key &p2) { return p2 < p1; }
inline bool operator<(const key_image &p1, const key_image &p2) { return memcmp(&p1, &p2, sizeof(key_image)) < 0; }
inline bool operator>(const key_image &p1, const key_image &p2) { return p2 < p1; }
}
// type conversions for easier calls to sc_add(), sc_sub(), hash functions
inline unsigned char* to_bytes(crypto::ec_scalar &scalar) { return &reinterpret_cast<unsigned char&>(scalar); }
inline const unsigned char* to_bytes(const crypto::ec_scalar &scalar) { return &reinterpret_cast<const unsigned char&>(scalar); }
inline unsigned char* to_bytes(crypto::ec_point &point) { return &reinterpret_cast<unsigned char&>(point); }
inline const unsigned char* to_bytes(const crypto::ec_point &point) { return &reinterpret_cast<const unsigned char&>(point); }
CRYPTO_MAKE_HASHABLE(public_key)
CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(secret_key)
CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(public_key_memsafe)
+7 -2
View File
@@ -33,6 +33,7 @@
#include <cstddef>
#include <cstring>
#include <functional>
#include <memory>
#include <sodium/crypto_verify_32.h>
#define CRYPTO_MAKE_COMPARABLE(type) \
@@ -60,14 +61,18 @@ namespace crypto { \
namespace crypto { \
static_assert(sizeof(std::size_t) <= sizeof(type), "Size of " #type " must be at least that of size_t"); \
inline std::size_t hash_value(const type &_v) { \
return reinterpret_cast<const std::size_t &>(_v); \
std::size_t h; \
memcpy(&h, std::addressof(_v), sizeof(h)); \
return h; \
} \
} \
namespace std { \
template<> \
struct hash<crypto::type> { \
std::size_t operator()(const crypto::type &_v) const { \
return reinterpret_cast<const std::size_t &>(_v); \
std::size_t h; \
memcpy(&h, std::addressof(_v), sizeof(h)); \
return h; \
} \
}; \
}
+11
View File
@@ -152,6 +152,17 @@ DISABLE_VS_WARNINGS(4244 4345)
m_keys.m_multisig_keys.clear();
}
//-----------------------------------------------------------------
void account_base::set_spend_key(const crypto::secret_key& spend_secret_key)
{
// make sure derived spend public key matches saved public spend key
crypto::public_key spend_public_key;
crypto::secret_key_to_public_key(spend_secret_key, spend_public_key);
CHECK_AND_ASSERT_THROW_MES(m_keys.m_account_address.m_spend_public_key == spend_public_key,
"Unexpected derived public spend key");
m_keys.m_spend_secret_key = spend_secret_key;
}
//-----------------------------------------------------------------
crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
{
crypto::secret_key first = generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, recovery_key, recover);
+1
View File
@@ -95,6 +95,7 @@ namespace cryptonote
bool store(const std::string& file_path);
void forget_spend_key();
void set_spend_key(const crypto::secret_key& spend_secret_key);
const std::vector<crypto::secret_key> &get_multisig_keys() const { return m_keys.m_multisig_keys; }
void encrypt_keys(const crypto::chacha_key &key) { m_keys.encrypt(key); }
@@ -29,6 +29,7 @@
#include "connection_context.h"
#include <boost/optional/optional.hpp>
#include "cryptonote_protocol/cryptonote_protocol_defs.h"
#include "p2p/p2p_protocol_defs.h"
@@ -69,4 +70,23 @@ namespace cryptonote
};
return std::numeric_limits<size_t>::max();
}
void cryptonote_connection_context::set_state_normal()
{
m_state = state_normal;
m_expected_heights_start = 0;
m_needed_objects.clear();
m_needed_objects.shrink_to_fit();
m_expected_heights.clear();
m_expected_heights.shrink_to_fit();
m_requested_objects.clear();
}
boost::optional<crypto::hash> cryptonote_connection_context::get_expected_hash(const uint64_t height) const
{
const auto difference = height - m_expected_heights_start;
if (height < m_expected_heights_start || m_expected_heights.size() < difference)
return boost::none;
return m_expected_heights[difference];
}
} // cryptonote
+9 -1
View File
@@ -34,6 +34,7 @@
#include <atomic>
#include <algorithm>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/optional/optional_fwd.hpp>
#include "net/net_utils_base.h"
#include "crypto/hash.h"
@@ -42,7 +43,7 @@ namespace cryptonote
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
{
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
m_expected_heights_start(0), m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_rpc_credits_per_hash(0), m_anchor(false), m_score(0),
m_expect_response(0), m_expect_height(0), m_num_requested(0) {}
@@ -92,11 +93,18 @@ namespace cryptonote
//! \return Maximum number of bytes permissible for `command`.
static size_t get_max_bytes(int command) noexcept;
//! Use this instead of `m_state = state_normal`.
void set_state_normal();
boost::optional<crypto::hash> get_expected_hash(uint64_t height) const;
state m_state;
std::vector<std::pair<crypto::hash, uint64_t>> m_needed_objects;
std::vector<crypto::hash> m_expected_heights;
std::unordered_set<crypto::hash> m_requested_objects;
uint64_t m_remote_blockchain_height;
uint64_t m_last_response_height;
uint64_t m_expected_heights_start;
boost::posix_time::ptime m_last_request_time;
copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
crypto::hash m_last_known_hash;
+28 -4
View File
@@ -200,8 +200,11 @@ namespace cryptonote
std::vector<uint8_t> extra;
// TX type
cryptonote::transaction_type type;
// Return address
crypto::public_key return_address;
// Return address list (must be at least 1 and at most BULLETPROOF_MAX_OUTPUTS-1 - the "-1" is for the change output)
std::vector<crypto::public_key> return_address_list;
//return_address_change_mask
std::vector<uint8_t> return_address_change_mask;
// Return TX public key
crypto::public_key return_pubkey;
// Source asset type
@@ -221,11 +224,18 @@ namespace cryptonote
FIELD(vout)
FIELD(extra)
VARINT_FIELD(type)
if (type != cryptonote::transaction_type::PROTOCOL) {
if (type != cryptonote::transaction_type::UNSET &&
type != cryptonote::transaction_type::PROTOCOL) {
VARINT_FIELD(amount_burnt)
if (type != cryptonote::transaction_type::MINER) {
FIELD(return_address)
FIELD(return_pubkey)
if (type == cryptonote::transaction_type::TRANSFER && version >= TRANSACTION_VERSION_N_OUTS) {
FIELD(return_address_list)
FIELD(return_address_change_mask)
} else {
FIELD(return_address)
FIELD(return_pubkey)
}
FIELD(source_asset_type)
FIELD(destination_asset_type)
VARINT_FIELD(amount_slippage_limit)
@@ -244,6 +254,8 @@ namespace cryptonote
extra.clear();
type = cryptonote::transaction_type::UNSET;
return_address = crypto::null_pkey;
return_address_list.clear();
return_address_change_mask.clear();
return_pubkey = crypto::null_pkey;
source_asset_type.clear();
destination_asset_type.clear();
@@ -500,6 +512,18 @@ namespace cryptonote
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
}
struct audit_block_info {
uint64_t block_height;
uint64_t locked_coins_this_block;
uint64_t locked_coins_tally;
BEGIN_SERIALIZE()
VARINT_FIELD(block_height)
VARINT_FIELD(locked_coins_this_block)
VARINT_FIELD(locked_coins_tally)
END_SERIALIZE()
};
struct yield_block_info {
uint64_t block_height;
uint64_t slippage_total_this_block;
@@ -70,8 +70,6 @@ namespace cryptonote {
{
if (version < 2)
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1;
if (version < 5)
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2;
return CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5;
}
//-----------------------------------------------------------------------------------------------
@@ -166,24 +166,7 @@ namespace boost
inline void serialize(Archive &a, cryptonote::transaction_prefix &x, const boost::serialization::version_type ver)
{
a & x.version;
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;
@@ -191,8 +174,39 @@ namespace boost
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;
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
a & x.return_address_list;
a & x.return_address_change_mask;
} else {
a & x.return_address;
a & x.return_pubkey;
}
a & x.source_asset_type;
a & x.destination_asset_type;
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 && x.type != cryptonote::transaction_type::UNSET) {
a & x.amount_burnt;
if (x.type != cryptonote::transaction_type::MINER) {
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
a & x.return_address_list;
a & x.return_address_change_mask;
} else {
a & x.return_address;
a & x.return_pubkey;
}
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_slippage_limit;
@@ -336,6 +350,36 @@ namespace boost
a & x.D;
}
template <class Archive>
inline void serialize(Archive &a, rct::zk_proof &x, const boost::serialization::version_type ver)
{
a & x.R;
a & x.z1;
a & x.z2;
}
template <class Archive>
inline void serialize(Archive &a, rct::salvium_input_data_t &x, const boost::serialization::version_type ver)
{
a & x.aR;
a & x.i;
}
template <class Archive>
inline void serialize(Archive &a, rct::salvium_data_t &x, const boost::serialization::version_type ver)
{
a & x.salvium_data_type;
a & x.pr_proof;
a & x.sa_proof;
if (x.salvium_data_type == rct::SalviumAudit)
{
a & x.cz_proof;
a & x.input_verification_data;
a & x.spend_pubkey;
a & x.enc_view_privkey_str;
}
}
template <class Archive>
inline void serialize(Archive &a, rct::ecdhTuple &x, const boost::serialization::version_type ver)
{
@@ -389,7 +433,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus)
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumOne)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -399,6 +443,12 @@ namespace boost
serializeOutPk(a, x.outPk, ver);
a & x.txnFee;
a & x.p_r;
if (x.type == rct::RCTTypeSalviumOne) {
a & x.salvium_data;
} else if (x.type == rct::RCTTypeFullProofs) {
a & x.salvium_data.pr_proof;
a & x.salvium_data.sa_proof;
}
}
template <class Archive>
@@ -424,7 +474,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus)
if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2 && x.type != rct::RCTTypeCLSAG && x.type != rct::RCTTypeBulletproofPlus && x.type != rct::RCTTypeFullProofs && x.type != rct::RCTTypeSalviumOne)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -434,6 +484,12 @@ namespace boost
serializeOutPk(a, x.outPk, ver);
a & x.txnFee;
a & x.p_r;
if (x.type == rct::RCTTypeSalviumOne) {
a & x.salvium_data;
} else if (x.type == rct::RCTTypeFullProofs) {
a & x.salvium_data.pr_proof;
a & x.salvium_data.sa_proof;
}
//--------------
a & x.p.rangeSigs;
if (x.p.rangeSigs.empty())
@@ -445,7 +501,7 @@ namespace boost
a & x.p.MGs;
if (ver >= 1u)
a & x.p.CLSAGs;
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus)
if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2 || x.type == rct::RCTTypeCLSAG || x.type == rct::RCTTypeBulletproofPlus || x.type == rct::RCTTypeFullProofs || x.type == rct::RCTTypeSalviumOne)
a & x.p.pseudoOuts;
}
@@ -487,5 +543,5 @@ namespace boost
}
BOOST_CLASS_VERSION(rct::rctSigPrunable, 2)
BOOST_CLASS_VERSION(rct::rctSig, 2)
BOOST_CLASS_VERSION(rct::rctSig, 4)
BOOST_CLASS_VERSION(rct::multisig_out, 1)
@@ -110,7 +110,7 @@ namespace cryptonote
uint64_t get_transaction_weight_clawback(const transaction &tx, size_t n_padded_outputs)
{
const rct::rctSig &rv = tx.rct_signatures;
const bool plus = rv.type == rct::RCTTypeBulletproofPlus;
const bool plus = (rv.type == rct::RCTTypeBulletproofPlus || rv.type == rct::RCTTypeFullProofs);
const uint64_t bp_base = (32 * ((plus ? 6 : 9) + 7 * 2)) / 2; // notional size of a 2 output proof, normalized to 1 proof (ie, divided by 2)
const size_t n_outputs = tx.vout.size();
if (n_padded_outputs <= 2)
@@ -290,13 +290,13 @@ 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, const bool use_origin_data, const origin_data& od)
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, rct::salvium_input_data_t& sid)
{
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);
if (!r)
{
MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", <viewkey>)");
memcpy(&recv_derivation, rct::identity().bytes, sizeof(recv_derivation));
}
@@ -307,7 +307,7 @@ namespace cryptonote
r = hwdev.generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation);
if (!r)
{
MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")");
MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", <viewkey>)");
}
else
{
@@ -317,11 +317,13 @@ 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, use_origin_data, od);
sid.aR = subaddr_recv_info->derivation;
sid.i = real_output_index;
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, sid);
}
//---------------------------------------------------------------
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)
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, rct::salvium_input_data_t& sid)
{
if (hwdev.compute_key_image(ack, out_key, recv_derivation, real_output_index, received_index, in_ephemeral, ki))
{
@@ -400,7 +402,7 @@ namespace cryptonote
// 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) {
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE || od.tx_type == cryptonote::transaction_type::AUDIT) {
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);
@@ -415,13 +417,20 @@ namespace cryptonote
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");
// 3.5 Handle subaddresses
if (!received_index.is_zero()) {
crypto::secret_key scalar_step3;
hwdev.sc_secret_add(scalar_step3, sk_spend, subaddr_sk);
sk_spend = scalar_step3;
}
// 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) {
if (od.tx_type == cryptonote::transaction_type::CONVERT || od.tx_type == cryptonote::transaction_type::STAKE || od.tx_type == cryptonote::transaction_type::AUDIT) {
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'");
@@ -433,7 +442,11 @@ namespace cryptonote
// 6. Create the key_image needed to be able to spend the output
hwdev.generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
// Update the SID to have the correct derivation for P_change as well
sid.aR_stake = derivation_P_change_tx;
sid.i_stake = od.output_index;
return true;
} else {
@@ -517,7 +530,7 @@ namespace cryptonote
{
CHECK_AND_ASSERT_MES(tx.pruned, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support non pruned txes");
CHECK_AND_ASSERT_MES(tx.version >= 2, std::numeric_limits<uint64_t>::max(), "get_pruned_transaction_weight does not support v1 txes");
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus,
CHECK_AND_ASSERT_MES(tx.rct_signatures.type == rct::RCTTypeBulletproof2 || tx.rct_signatures.type == rct::RCTTypeCLSAG || tx.rct_signatures.type == rct::RCTTypeBulletproofPlus || tx.rct_signatures.type == rct::RCTTypeFullProofs,
std::numeric_limits<uint64_t>::max(), "Unsupported rct_signatures type in get_pruned_transaction_weight");
CHECK_AND_ASSERT_MES(!tx.vin.empty(), std::numeric_limits<uint64_t>::max(), "empty vin");
CHECK_AND_ASSERT_MES(tx.vin[0].type() == typeid(cryptonote::txin_to_key), std::numeric_limits<uint64_t>::max(), "empty vin");
@@ -967,8 +980,8 @@ namespace cryptonote
switch (asset_type_id) {
case 0x53414C00:
return "SAL";
case 0x56534400:
return "VSD";
case 0x53414C31:
return "SAL1";
case 0x4255524E:
return "BURN";
case 0x00000000:
@@ -984,8 +997,8 @@ namespace cryptonote
{
if (asset_type == "SAL") {
return 0x53414C00;
} else if (asset_type == "VSD") {
return 0x56534400;
} else if (asset_type == "SAL1") {
return 0x53414C31;
} else if (asset_type == "BURN") {
return 0x4255524E;
} else if (asset_type == "") {
@@ -1230,37 +1243,62 @@ namespace cryptonote
//---------------------------------------------------------------
bool check_output_types(const transaction& tx, const uint8_t hf_version)
{
if (tx.type == cryptonote::transaction_type::AUDIT || tx.type == cryptonote::transaction_type::STAKE) {
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "audit and stake transactions should have 1 output");
}
for (const auto &o: tx.vout)
{
if (hf_version > HF_VERSION_VIEW_TAGS)
if (hf_version > HF_VERSION_REQUIRE_VIEW_TAGS)
{
// from v15, require outputs have view tags
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_tagged_key in transaction id=" << get_transaction_hash(tx));
<< o.target.type().name() << ", expected txout_to_tagged_key in transaction");
}
else if (hf_version < HF_VERSION_VIEW_TAGS)
{
// require outputs to be of type txout_to_key
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_key in transaction id=" << get_transaction_hash(tx));
<< o.target.type().name() << ", expected txout_to_key in transaction");
}
else //(hf_version == HF_VERSION_VIEW_TAGS)
else //(hf_version == HF_VERSION_VIEW_TAGS || hf_version == HF_VERSION_VIEW_TAGS+1)
{
// require outputs be of type txout_to_key OR txout_to_tagged_key
// to allow grace period before requiring all to be txout_to_tagged_key
CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_to_tagged_key), false, "wrong variant type: "
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction id=" << get_transaction_hash(tx));
<< o.target.type().name() << ", expected txout_to_key or txout_to_tagged_key in transaction");
// require all outputs in a tx be of the same type
CHECK_AND_ASSERT_MES(o.target.type() == tx.vout[0].target.type(), false, "non-matching variant types: "
<< o.target.type().name() << " and " << tx.vout[0].target.type().name() << ", "
<< "expected matching variant types in transaction id=" << get_transaction_hash(tx));
<< "expected matching variant types in transaction");
}
// Verify the asset type
std::string asset_type;
CHECK_AND_ASSERT_MES(cryptonote::get_output_asset_type(o, asset_type), false, "failed to get asset type");
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
if (hf_version < HF_VERSION_SALVIUM_ONE_PROOFS) {
// Prior to the first audit, ONLY SAL was supported
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
} else {
if (tx.type == cryptonote::transaction_type::AUDIT) {
// HERE BE DRAGONS!!!
// SRCG: This will NOT always be the case - when we add an audit for SALx it'll need to support that as well
// The CHANGE for an AUDIT TX must be SAL (and 0 value, and unspendable, and to the origin wallet, and ...)
CHECK_AND_ASSERT_MES(asset_type == "SAL", false, "wrong output asset type:" << asset_type);
// LAND AHOY!!!
} else if (tx.type == cryptonote::transaction_type::PROTOCOL) {
if (hf_version < HF_VERSION_AUDIT1_PAUSE) {
// PROTOCOL TXs are responsible for paying out SAL and SAL1 during the first AUDIT
CHECK_AND_ASSERT_MES(asset_type == "SAL1" || asset_type == "SAL", false, "wrong output asset type:" << asset_type);
} else {
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
}
} else {
// All other TX types must only spend + create SAL1 (MINER, TRANSFER)
CHECK_AND_ASSERT_MES(asset_type == "SAL1", false, "wrong output asset type:" << asset_type);
}
}
}
return true;
}
@@ -1338,15 +1376,13 @@ 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 we get here, odds are that it is a PROTOCOL_TX
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");
@@ -1724,7 +1760,7 @@ namespace cryptonote
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
crypto::hash tree_root_hash = get_tx_tree_hash(b);
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
blob.append(tools::get_varint_data(b.tx_hashes.size() + (b.major_version >= HF_VERSION_ENABLE_N_OUTS ? 2 : 1)));
return blob;
}
//---------------------------------------------------------------
@@ -104,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, 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);
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, rct::salvium_input_data_t& sid);
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, rct::salvium_input_data_t& sid);
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);
+58
View File
@@ -33,6 +33,7 @@
#include <cstddef>
#include <cstdint>
#include <vector>
#include <boost/math/special_functions/round.hpp>
#include "int-util.h"
#include "crypto/hash.h"
@@ -239,6 +240,63 @@ namespace cryptonote {
return res.convert_to<difficulty_type>();
}
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
// LWMA difficulty algorithm
// Copyright (c) 2017-2018 Zawy
// MIT license http://www.opensource.org/licenses/mit-license.php.
// This is an improved version of Tom Harding's (Deger8) "WT-144"
// Karbowanec, Masari, Bitcoin Gold, and Bitcoin Cash have contributed.
// See https://github.com/zawy12/difficulty-algorithms/issues/3 for other algos.
// Do not use "if solvetime < 0 then solvetime = 1" which allows a catastrophic exploit.
// T= target_solvetime;
// N=45, 55, 70, 90, 120 for T=600, 240, 120, 90, and 60
const int64_t T = static_cast<int64_t>(target_seconds);
size_t N = DIFFICULTY_WINDOW_V2;
if (timestamps.size() > N) {
timestamps.resize(N + 1);
cumulative_difficulties.resize(N + 1);
}
size_t n = timestamps.size();
assert(n == cumulative_difficulties.size());
assert(n <= DIFFICULTY_WINDOW_V2);
// If new coin, just "give away" first 5 blocks at low difficulty
if ( n < 6 ) { return 1; }
// If height "n" is from 6 to N, then reset N to n-1.
else if (n < N+1) { N=n-1; }
// To get an average solvetime to within +/- ~0.1%, use an adjustment factor.
// adjust=0.99 for 90 < N < 130
const long double adjust = 0.998;
// The divisor k normalizes LWMA.
const long double k = N * (N + 1) / 2;
long double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0);
int64_t solveTime(0);
uint64_t difficulty(0), next_difficulty(0);
// Loop through N most recent blocks.
for (size_t i = 1; i <= N; i++) {
solveTime = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i - 1]);
solveTime = std::min<int64_t>((T * 7), std::max<int64_t>(solveTime, (-7 * T)));
difficulty = (cumulative_difficulties[i] - cumulative_difficulties[i - 1]).convert_to<uint64_t>();
LWMA += (int64_t)(solveTime * i) / k;
sum_inverse_D += 1 / static_cast<double>(difficulty);
}
// Keep LWMA sane in case something unforeseen occurs.
if (static_cast<int64_t>(boost::math::round(LWMA)) < T / 20)
LWMA = static_cast<double>(T / 20);
harmonic_mean_D = N / sum_inverse_D * adjust;
nextDifficulty = harmonic_mean_D * T / LWMA;
next_difficulty = static_cast<uint64_t>(nextDifficulty);
return next_difficulty;
}
std::string hex(difficulty_type v)
{
static const char chars[] = "0123456789abcdef";
+2 -1
View File
@@ -58,6 +58,7 @@ namespace cryptonote
bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty);
bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
std::string hex(difficulty_type v);
}
@@ -59,6 +59,7 @@ namespace cryptonote
bool m_fee_too_low;
bool m_too_few_outputs;
bool m_tx_extra_too_big;
bool m_version_mismatch; // TX version wrong for the currently-active HF version
};
struct block_verification_context
+53 -7
View File
@@ -31,6 +31,7 @@
#pragma once
#include <array>
#include <map>
#include <stdexcept>
#include <string>
#include <boost/uuid/uuid.hpp>
@@ -42,7 +43,9 @@
#define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
#define CURRENT_TRANSACTION_VERSION 2
#define CURRENT_TRANSACTION_VERSION 3
#define TRANSACTION_VERSION_2_OUTS 2
#define TRANSACTION_VERSION_N_OUTS 3
#define CURRENT_BLOCK_MAJOR_VERSION 1
#define CURRENT_BLOCK_MINOR_VERSION 1
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
@@ -85,9 +88,11 @@
#define DIFFICULTY_TARGET_V2 120 // seconds
#define DIFFICULTY_TARGET_V1 60 // seconds - before first fork
#define DIFFICULTY_WINDOW_V2 70 // blocks
#define DIFFICULTY_WINDOW 720 // blocks
#define DIFFICULTY_LAG 15 // !!!
#define DIFFICULTY_CUT 60 // timestamps to cut after sorting
#define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2
#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG
@@ -133,6 +138,10 @@
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_BLOCK_COUNT 1000
#define COMMAND_RPC_GET_BLOCKS_FAST_MAX_TX_COUNT 20000
#define DEFAULT_RPC_MAX_CONNECTIONS_PER_PUBLIC_IP 3
#define DEFAULT_RPC_MAX_CONNECTIONS_PER_PRIVATE_IP 25
#define DEFAULT_RPC_MAX_CONNECTIONS 100
#define DEFAULT_RPC_SOFT_LIMIT_SIZE 25 * 1024 * 1024 // 25 MiB
#define MAX_RPC_CONTENT_LENGTH 1048576 // 1 MB
#define P2P_LOCAL_WHITE_PEERLIST_LIMIT 1000
@@ -173,6 +182,9 @@
#define THREAD_STACK_SIZE 5 * 1024 * 1024
#define SECRET_ENCRYPTION_PK_STR "5e860406bf9221dba6409faa6eb8fecd6f34acc4935634e76b64b90bf2b6d6a6"
/*
#define HF_VERSION_DYNAMIC_FEE 4
#define HF_VERSION_MIN_MIXIN_4 6
@@ -212,11 +224,27 @@
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT 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 HF_VERSION_ENABLE_N_OUTS 2
#define TESTNET_VERSION 11
#define HF_VERSION_FULL_PROOFS 3
#define HF_VERSION_ENFORCE_FULL_PROOFS 4
#define HF_VERSION_SHUTDOWN_USER_TXS 5
#define HF_VERSION_AUDIT1 6
#define HF_VERSION_SALVIUM_ONE_PROOFS 6
#define HF_VERSION_AUDIT1_PAUSE 7
#define HF_VERSION_AUDIT2 8
#define HF_VERSION_AUDIT2_PAUSE 9
#define HF_VERSION_REQUIRE_VIEW_TAGS 255
#define HF_VERSION_ENABLE_CONVERT 255
#define HF_VERSION_ENABLE_ORACLE 255
#define HF_VERSION_SLIPPAGE_YIELD 255
#define TESTNET_VERSION 14
#define STAGENET_VERSION 1
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
@@ -267,10 +295,15 @@ namespace config
uint32_t const GENESIS_NONCE = 10000;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = {
{HF_VERSION_AUDIT1, {30*24*10, {"SAL", "SAL1"}}},
{HF_VERSION_AUDIT2, {30*24*14, {"SAL", "SAL1"}}}
};
const uint64_t STAKE_LOCK_PERIOD = 30*24*30;
std::string const TREASURY_ADDRESS = "SaLvdZR6w1A21sf2Wh6jYEh1wzY4GSbT7RX6FjyPsnLsffWLrzFQeXUXJcmBLRWDzZC2YXeYe5t7qKsnrg9FpmxmEcxPHsEYfqA";
// Hash domain separators
const char HASH_KEY_BULLETPROOF_EXPONENT[] = "bulletproof";
const char HASH_KEY_BULLETPROOF_PLUS_EXPONENT[] = "bulletproof_plus";
@@ -280,6 +313,8 @@ namespace config
const unsigned char HASH_KEY_ENCRYPTED_PAYMENT_ID = 0x8d;
const unsigned char HASH_KEY_WALLET = 0x8c;
const unsigned char HASH_KEY_WALLET_CACHE = 0x8d;
const unsigned char HASH_KEY_BACKGROUND_CACHE = 0x8e;
const unsigned char HASH_KEY_BACKGROUND_KEYS_FILE = 0x8f;
const unsigned char HASH_KEY_RPC_PAYMENT_NONCE = 0x58;
const unsigned char HASH_KEY_MEMORY = 'k';
const unsigned char HASH_KEY_MULTISIG[] = {'M', 'u', 'l', 't' , 'i', 's', 'i', 'g', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -340,6 +375,11 @@ namespace config
std::string const GENESIS_TX = "020001ff000180c0d0c7bbbff60302838f76f69b70bb0d0f1961a12f6082a033d22285c07d4f12ec93c28197ae2a600353414c3c2101009e8b0abce686c417a1b1344eb7337176bdca90cc928b0facec8a9516190645010000";
uint32_t const GENESIS_NONCE = 10001;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = {
{HF_VERSION_AUDIT1, {30, {"SAL", "SAL1"}}},
{HF_VERSION_AUDIT2, {40, {"SAL", "SAL1"}}},
};
const uint64_t STAKE_LOCK_PERIOD = 20;
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
@@ -366,6 +406,8 @@ namespace config
std::string const GENESIS_TX = "013c01ff0001ffffffffffff0302df5d56da0c7d643ddd1ce61901c7bdc5fb1738bfe39fbe69c28a3a7032729c0f2101168d0c4ca86fb55a4cf6a36d31431be1c53a3bd7411bb24e8832410289fa6f3b";
uint32_t const GENESIS_NONCE = 10002;
const std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> AUDIT_HARD_FORKS = { {HF_VERSION_AUDIT1, {30, {"SAL", "SAL1"}}} };
const uint64_t STAKE_LOCK_PERIOD = 20;
std::array<std::string, 3> const ORACLE_URLS = {{"oracle.salvium.io:8443", "oracle.salvium.io:8443", "oracle.salvium.io:8443"}};
@@ -402,7 +444,8 @@ namespace cryptonote
uint32_t const GENESIS_NONCE;
std::array<std::string, 3> const ORACLE_URLS;
std::string const ORACLE_PUBLIC_KEY;
uint64_t STAKE_LOCK_PERIOD;
uint64_t const STAKE_LOCK_PERIOD;
std::map<uint8_t, std::pair<uint64_t, std::pair<std::string, std::string>>> const AUDIT_HARD_FORKS;
std::string TREASURY_ADDRESS;
};
inline const config_t& get_config(network_type nettype)
@@ -420,6 +463,7 @@ namespace cryptonote
::config::ORACLE_URLS,
::config::ORACLE_PUBLIC_KEY,
::config::STAKE_LOCK_PERIOD,
::config::AUDIT_HARD_FORKS,
::config::TREASURY_ADDRESS
};
static const config_t testnet = {
@@ -435,6 +479,7 @@ namespace cryptonote
::config::testnet::ORACLE_URLS,
::config::testnet::ORACLE_PUBLIC_KEY,
::config::testnet::STAKE_LOCK_PERIOD,
::config::testnet::AUDIT_HARD_FORKS,
::config::testnet::TREASURY_ADDRESS
};
static const config_t stagenet = {
@@ -450,6 +495,7 @@ namespace cryptonote
::config::stagenet::ORACLE_URLS,
::config::stagenet::ORACLE_PUBLIC_KEY,
::config::stagenet::STAKE_LOCK_PERIOD,
::config::stagenet::AUDIT_HARD_FORKS,
::config::stagenet::TREASURY_ADDRESS
};
switch (nettype)
File diff suppressed because it is too large Load Diff
+34 -5
View File
@@ -29,7 +29,8 @@
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
#pragma once
#include <boost/asio/io_service.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/function/function_fwd.hpp>
#if BOOST_VERSION >= 107400
#include <boost/serialization/library_version_type.hpp>
@@ -725,6 +726,19 @@ namespace cryptonote
*/
bool check_tx_outputs(const transaction& tx, tx_verification_context &tvc) const;
/**
* @brief check that a transaction's version & type conforms to current standards
*
* This function checks, for example at the time of this writing, that
* the TX version and type is supported by the current HF version on-chain.
*
* @param tx the transaction to check the version and type of
* @param tvc returned info about tx verification
*
* @return false if the TX version and/or type is unsupported, otherwise true
*/
bool check_tx_type_and_version(const transaction& tx, tx_verification_context &tvc) const;
/**
* @brief gets the block weight limit based on recent blocks
*
@@ -1147,6 +1161,13 @@ namespace cryptonote
*/
uint64_t get_adjusted_time(uint64_t height) const;
/**
* calculate the audit payouts
*
* @return TRUE if the payouts were calculated successfully, FALSE otherwise
*/
bool calculate_audit_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& audit_payouts);
/**
* calculate the yield payouts
*
@@ -1154,6 +1175,15 @@ namespace cryptonote
*/
bool calculate_yield_payouts(const uint64_t start_height, std::vector<std::pair<yield_tx_info, uint64_t>>& yield_payouts);
/**
* @brief get the ABI entry for a particular height from the cache
*
* Retrieve the ABI entry for the specified height from the local cache.
*
* @return TRUE if the entry was located and returned, FALSE otherwise
*/
bool get_abi_entry(const uint64_t height, cryptonote::audit_block_info& ybi);
/**
* @brief get the complete YBI cache
*
@@ -1251,9 +1281,9 @@ namespace cryptonote
crypto::hash m_difficulty_for_next_block_top_hash;
difficulty_type m_difficulty_for_next_block;
boost::asio::io_service m_async_service;
boost::asio::io_context m_async_service;
boost::thread_group m_async_pool;
std::unique_ptr<boost::asio::io_service::work> m_async_work_idle;
std::unique_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> m_async_work_idle;
// some invalid blocks
blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info
@@ -1516,12 +1546,11 @@ namespace cryptonote
*
* @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, uint8_t hf_version);
bool validate_protocol_transaction(const block& b, uint64_t height, uint8_t hf_version);
/**
* @brief reverts the blockchain to its previous state following a failed switch
+25 -3
View File
@@ -842,8 +842,8 @@ 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 < HF_VERSION_SLIPPAGE_YIELD) ? 2 : CURRENT_TRANSACTION_VERSION;
uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = (hf_version >= HF_VERSION_ENABLE_N_OUTS) ? TRANSACTION_VERSION_N_OUTS : TRANSACTION_VERSION_2_OUTS;
if (tx.version == 0 || tx.version > max_tx_version)
{
// v2 is the latest one we know
@@ -923,6 +923,24 @@ namespace cryptonote
if (tx_info[n].tx->version < 2)
continue;
const rct::rctSig &rv = tx_info[n].tx->rct_signatures;
const uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
if (hf_version >= HF_VERSION_SALVIUM_ONE_PROOFS) {
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeSalviumOne) {
MERROR_VER("Invalid RCT type provided");
set_semantics_failed(tx_info[n].tx_hash);
tx_info[n].tvc.m_verifivation_failed = true;
tx_info[n].result = false;
return false;
}
} else if (hf_version >= HF_VERSION_ENFORCE_FULL_PROOFS) {
if (rv.type != rct::RCTTypeNull && rv.type != rct::RCTTypeFullProofs) {
MERROR_VER("Invalid RCT type provided");
set_semantics_failed(tx_info[n].tx_hash);
tx_info[n].tvc.m_verifivation_failed = true;
tx_info[n].result = false;
return false;
}
}
switch (rv.type) {
case rct::RCTTypeNull:
// coinbase should not come here, so we reject for all other types
@@ -936,6 +954,7 @@ namespace cryptonote
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 :
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
0
))
{
@@ -970,6 +989,8 @@ namespace cryptonote
rvv.push_back(&rv); // delayed batch verification
break;
case rct::RCTTypeBulletproofPlus:
case rct::RCTTypeFullProofs:
case rct::RCTTypeSalviumOne:
if (!is_canonical_bulletproof_plus_layout(rv.p.bulletproofs_plus))
{
MERROR_VER("Bulletproof_plus does not have canonical form");
@@ -996,12 +1017,13 @@ namespace cryptonote
{
if (!tx_info[n].result)
continue;
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus)
if (tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproof2 && tx_info[n].tx->rct_signatures.type != rct::RCTTypeCLSAG && tx_info[n].tx->rct_signatures.type != rct::RCTTypeBulletproofPlus && tx_info[n].tx->rct_signatures.type != rct::RCTTypeFullProofs && tx_info[n].tx->rct_signatures.type != rct::RCTTypeSalviumOne)
continue;
if (!rct::verRctSemanticsSimple(tx_info[n].tx->rct_signatures,
tx_info[n].tx->type == cryptonote::transaction_type::BURN ? tx_info[n].tx->amount_burnt :
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 :
tx_info[n].tx->type == cryptonote::transaction_type::AUDIT ? tx_info[n].tx->amount_burnt :
0
))
{
+284 -224
View File
@@ -46,6 +46,11 @@ using namespace epee;
#include "ringct/rctSigs.h"
#include "oracle/asset_types.h"
extern "C"
{
#include "crypto/keccak.h"
#include "crypto/crypto-ops.h"
}
using namespace crypto;
namespace cryptonote
@@ -110,7 +115,7 @@ namespace cryptonote
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)
{
@@ -203,7 +208,7 @@ namespace cryptonote
// We are done here - return to caller
return true;
} else if (tx_type == cryptonote::transaction_type::STAKE) {
} else if (tx_type == cryptonote::transaction_type::STAKE || tx_type == cryptonote::transaction_type::AUDIT) {
// CONVERT / YIELD Semantics
// From this point forward, we are departing from the original "return address" scheme
@@ -254,6 +259,7 @@ namespace cryptonote
// 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
@@ -327,19 +333,14 @@ namespace cryptonote
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;
bool construct_protocol_tx(
const size_t height,
transaction& tx,
std::vector<protocol_data_entry>& protocol_data,
const uint8_t hf_version
) {
// Clear the TX contents
tx.set_null();
@@ -353,174 +354,33 @@ namespace cryptonote
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, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
} else {
// 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, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
}
} else if (entry.type == cryptonote::transaction_type::STAKE) {
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, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
} else if (entry.type == cryptonote::transaction_type::AUDIT) {
// PAYOUT
LOG_PRINT_L2("Audit TX payout submitted " << entry.amount_burnt << entry.source_asset);
// Create the TX output for this refund
tx_out out;
cryptonote::set_tx_out(entry.amount_burnt, entry.destination_asset, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, entry.return_address, false, crypto::view_tag{}, out);
additional_tx_public_keys.push_back(entry.return_pubkey);
tx.vout.push_back(out);
}
}
// 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", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, 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", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, 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;
@@ -564,7 +424,7 @@ namespace cryptonote
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(r, false, "while creating outs: failed to generate_key_derivation(" << miner_address.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{txkey.sec} << ")");
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 << ")");
@@ -572,10 +432,10 @@ namespace cryptonote
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, 0, view_tag);
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, 0, view_tag);
// Should we award some of the block reward to the stakers?
if (height != 0) {
@@ -583,6 +443,14 @@ namespace cryptonote
// Different forks take a different proportion of the block_reward for stakers
switch (hard_fork_version) {
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
case HF_VERSION_FULL_PROOFS:
case HF_VERSION_ENFORCE_FULL_PROOFS:
case HF_VERSION_SHUTDOWN_USER_TXS:
case HF_VERSION_SALVIUM_ONE_PROOFS:
case HF_VERSION_AUDIT1_PAUSE:
case HF_VERSION_AUDIT2:
case HF_VERSION_AUDIT2_PAUSE:
// 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;
@@ -593,7 +461,10 @@ namespace cryptonote
}
tx_out out;
cryptonote::set_tx_out(amount, "SAL", CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
std::string asset_type = "SAL";
if (hard_fork_version >= HF_VERSION_SALVIUM_ONE_PROOFS)
asset_type = "SAL1";
cryptonote::set_tx_out(amount, asset_type, CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, out_eph_public_key, use_view_tags, view_tag, out);
tx.vout.push_back(out);
} else {
@@ -639,6 +510,83 @@ namespace cryptonote
return addr.m_view_public_key;
}
//---------------------------------------------------------------
// Encrypt function
std::string encrypt_pvk(const crypto::secret_key &pvk, const crypto::public_key &PK) {
// Step 1: Generate ephemeral keypair
crypto::secret_key ephemeral_sk;
crypto::public_key ephemeral_pk;
crypto::generate_keys(ephemeral_pk, ephemeral_sk);
// Step 2: Derive shared secret
crypto::ec_scalar shared_secret;
crypto::key_derivation derivation;
if (!crypto::generate_key_derivation(PK, ephemeral_sk, derivation)) {
throw std::runtime_error("Failed to generate key derivation");
}
crypto::derivation_to_scalar(derivation, 0, shared_secret);
// Step 3: Symmetric key generation (using Keccak hash)
crypto::hash symmetric_key_hash;
crypto::cn_fast_hash(&shared_secret, sizeof(shared_secret), symmetric_key_hash);
// Step 4: Encrypt the data (AES-256-CBC or ChaCha20)
std::string ciphertext(sizeof(crypto::secret_key), '\0');
crypto::chacha_key symmetric_key;
memcpy(&symmetric_key, &symmetric_key_hash, sizeof(symmetric_key));
crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>();
crypto::chacha20(pvk.data, sizeof(crypto::secret_key), symmetric_key, iv, &ciphertext[0]);
// Step 5: Package ephemeral_pk and ciphertext together
std::string encrypted_data = std::string(reinterpret_cast<char*>(&ephemeral_pk), sizeof(ephemeral_pk)) +
std::string(reinterpret_cast<char*>(&iv), sizeof(iv)) +
ciphertext;
return epee::string_tools::buff_to_hex_nodelimer(encrypted_data);
}
//---------------------------------------------------------------
// Decrypt function
bool decrypt_pvk(const std::string &encrypted_data_hex, const crypto::secret_key &SK, crypto::secret_key &pvk) {
//std::string decrypt_pvk(const std::string &encrypted_data, const crypto::secret_key &SK) {
// Step 1: Extract ephemeral_pk, iv, and ciphertext from encrypted_data
std::string encrypted_data;
for (size_t i = 0; i < encrypted_data_hex.length(); i += 2) {
std::istringstream iss(encrypted_data_hex.substr(i, 2));
int byte;
iss >> std::hex >> byte;
encrypted_data += static_cast<char>(byte);
}
const char *data_ptr = encrypted_data.data();
crypto::public_key ephemeral_pk;
memcpy(&ephemeral_pk, data_ptr, sizeof(ephemeral_pk));
data_ptr += sizeof(ephemeral_pk);
crypto::chacha_iv iv;
memcpy(&iv, data_ptr, sizeof(iv));
data_ptr += sizeof(iv);
std::string ciphertext(data_ptr, encrypted_data.size() - sizeof(ephemeral_pk) - sizeof(iv));
// Step 2: Derive shared secret
crypto::ec_scalar shared_secret;
crypto::key_derivation derivation;
if (!crypto::generate_key_derivation(ephemeral_pk, SK, derivation)) {
throw std::runtime_error("Failed to generate key derivation");
}
crypto::derivation_to_scalar(derivation, 0, shared_secret);
// Step 3: Symmetric key generation (using Keccak hash)
crypto::hash symmetric_key_hash;
crypto::cn_fast_hash(&shared_secret, sizeof(shared_secret), symmetric_key_hash);
// Step 4: Decrypt the data
std::string plaintext(ciphertext.size(), '\0');
crypto::chacha_key symmetric_key;
memcpy(&symmetric_key, &symmetric_key_hash, sizeof(symmetric_key));
crypto::chacha20(ciphertext.data(), ciphertext.size(), symmetric_key, iv, &plaintext[0]);
memcpy(pvk.data, &plaintext[0], sizeof(crypto::secret_key));
return true;
}
//---------------------------------------------------------------
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();
@@ -653,8 +601,11 @@ namespace cryptonote
tx.set_null();
amount_keys.clear();
if (hf_version >= HF_VERSION_SLIPPAGE_YIELD) {
tx.version = 3;
tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
// Configure the correct TX version for the current HF + TX type
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
tx.version = TRANSACTION_VERSION_N_OUTS;
} else {
tx.version = 2;
}
@@ -662,8 +613,6 @@ namespace cryptonote
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;
@@ -749,6 +698,23 @@ namespace cryptonote
};
std::vector<input_generation_context_data> in_contexts;
bool audit = (tx_type == cryptonote::transaction_type::AUDIT);
rct::salvium_data_t salvium_data;
if (audit) {
// Generate the encrypted private view key
crypto::public_key PK;
epee::string_tools::hex_to_pod(SECRET_ENCRYPTION_PK_STR, PK);
salvium_data.enc_view_privkey_str = encrypt_pvk(sender_account_keys.m_view_secret_key, PK);
// And now the rest of the structure
salvium_data.salvium_data_type = rct::SalviumAudit;
salvium_data.input_verification_data.reserve(sources.size());
salvium_data.spend_pubkey = sender_account_keys.m_account_address.m_spend_public_key;
} else {
salvium_data.salvium_data_type = rct::SalviumNormal;
}
uint64_t summary_inputs_money = 0;
//fill inputs
int idx = -1;
@@ -766,14 +732,26 @@ namespace cryptonote
in_contexts.push_back(input_generation_context_data());
keypair& in_ephemeral = in_contexts.back().in_ephemeral;
crypto::key_image img;
rct::salvium_input_data_t sid;
const auto& out_key = reinterpret_cast<const crypto::public_key&>(src_entr.outputs[src_entr.real_output].second.dest);
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))
sid.origin_tx_type = src_entr.origin_tx_data.tx_type;
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, sid))
{
LOG_ERROR("Key image generation failed!");
return false;
}
// SRCG: store the audit data for the source here
if (audit) {
sid.amount = src_entr.amount;
if (sid.origin_tx_type == cryptonote::transaction_type::STAKE) {
// STAKE TXs have to use "output_index 0" because they don't know what the actual output_index value will be ahead of time
sid.i = 0;
}
salvium_data.input_verification_data.push_back(sid);
}
//check that derivated key is equal with real output key
if(!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) )
{
@@ -799,6 +777,14 @@ namespace cryptonote
tx.vin.push_back(input_to_key);
}
// Sanity check the size of the verification data
if (audit) {
if (salvium_data.input_verification_data.size() != sources.size()) {
LOG_ERROR("Missing input verification data");
return false;
}
}
if (shuffle_outs)
{
std::shuffle(destinations.begin(), destinations.end(), crypto::random_device{});
@@ -817,6 +803,7 @@ namespace cryptonote
std::swap(tx.vin[i0], tx.vin[i1]);
std::swap(in_contexts[i0], in_contexts[i1]);
std::swap(sources[i0], sources[i1]);
if (audit) std::swap(salvium_data.input_verification_data[i0], salvium_data.input_verification_data[i1]);
});
// figure out if we need to make additional tx pubkeys
@@ -849,7 +836,10 @@ namespace cryptonote
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = 0;
size_t change_index = 0;
crypto::secret_key x_change = crypto::null_skey;
rct::key key_yF;
uint8_t change_index = 0;
bool found_change = false;
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);
@@ -870,17 +860,25 @@ namespace cryptonote
tx.amount_burnt += dst_entr.amount;
continue;
}
} else if (tx_type == cryptonote::transaction_type::AUDIT) {
// 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) {
CHECK_AND_ASSERT_MES(!found_change, false, "Too many change outputs!!!");
change_index = output_index;
found_change = true;
}
LOG_ERROR("*****************************************************************************");
LOG_ERROR("in construct_tx_With_tx_key()");
LOG_ERROR("TX type : TRANSFER");
LOG_ERROR("tx_key : " << tx_key);
LOG_ERROR("tx_key : " << crypto::secret_key_explicit_print_ref{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);
@@ -902,14 +900,93 @@ 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) {
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
if (hf_version >= HF_VERSION_FULL_PROOFS) {
// Get the secret spend key for the change element
crypto::secret_key spend_skey = crypto::null_skey;
if (sender_account_keys.m_multisig_keys.empty())
{
// if not multisig, use normal spend skey
spend_skey = sender_account_keys.m_spend_secret_key;
}
else
{
// if multisig, use sum of multisig privkeys (local account's share of aggregate spend key)
for (const auto &multisig_key : sender_account_keys.m_multisig_keys)
{
sc_add((unsigned char*)spend_skey.data,
(const unsigned char*)multisig_key.data,
(const unsigned char*)spend_skey.data);
}
}
// Obtain a separate key_derivation for the P_change output
// (using the TX public key and the sender's private view key)
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
CHECK_AND_ASSERT_MES(hwdev.generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation), false, "Failed to generate key_derivation for P_change");
// Calculate the secret spend key "x_change" for the P_change output
CHECK_AND_ASSERT_MES(hwdev.derive_secret_key(derivation, change_index, spend_skey, x_change), false, "Failed to derive secret key for P_change");
}
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
CHECK_AND_ASSERT_MES(tx.vout.size() >= 2, false, "Internal error - too few outputs for TRANSFER 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");
// Calculate the F points and change mask for every destination
for (size_t op_index=0; op_index<tx.vout.size(); ++op_index) {
// Calculate the y value for return_payment support
ec_scalar y;
struct {
char domain_separator[8];
rct::key amount_key;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 7);
buf.amount_key = amount_keys[op_index];
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// Now generate the return address (and TX pubkey, although we will discard that)
crypto::public_key F = crypto::null_pkey;
crypto::public_key F_txpubkey = crypto::null_pkey;
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, y, sender_account_keys, P_change, additional_tx_public_keys[op_index], F, F_txpubkey, hwdev), false, "Failed to get return_address");
// Push the F point into the TX vector of F points
tx.return_address_list.push_back(F);
// Calculate the shared secret yF
if (hf_version >= HF_VERSION_FULL_PROOFS) {
rct::key key_aP = rct::scalarmultKey(rct::pk2rct(P_change), rct::sk2rct(sender_account_keys.m_view_secret_key));
key_yF = rct::hash_to_scalar(key_aP);
}
// Calculate the encrypted_change_index data for this output
struct {
char domain_separator[8];
rct::key amount_key;
} eci_buf;
std::memset(eci_buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(eci_buf.domain_separator, "CHG_IDX", 8);
eci_buf.amount_key = amount_keys[op_index];
crypto::secret_key eci_out;
keccak((uint8_t *)&eci_buf, sizeof(eci_buf), (uint8_t*)&eci_out, sizeof(eci_out));
uint8_t eci_data = change_index ^ eci_out.data[0];
tx.return_address_change_mask.push_back(eci_data);
}
} else if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT) {
// 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");
else if (tx.type == cryptonote::transaction_type::STAKE || tx.type == cryptonote::transaction_type::AUDIT)
CHECK_AND_ASSERT_MES(tx.vout.size() == 1, false, "Internal error - incorrect number of outputs (!=1) for STAKE/AUDIT 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");
@@ -987,7 +1064,7 @@ namespace cryptonote
crypto::generate_ring_signature(tx_prefix_hash, boost::get<txin_to_key>(tx.vin[i]).k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data());
ss_ring_s << "signatures:" << ENDL;
std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;});
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL;
ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << crypto::secret_key_explicit_print_ref{in_contexts[i].in_ephemeral.sec} << ENDL << "real_output: " << src_entr.real_output << ENDL;
i++;
}
@@ -1097,31 +1174,11 @@ namespace cryptonote
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)
{
for (size_t i = 0; i < tx.vin.size(); ++i) {
if (sources[i].rct)
boost::get<txin_to_key>(tx.vin[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;
}
@@ -1130,23 +1187,26 @@ namespace cryptonote
rct::ctkeyV outSk;
if (use_simple_rct)
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
);
rct::hash2rct(tx_prefix_hash),
inSk,
destinations,
tx_type,
source_asset,
destination_asset_types,
inamounts,
outamounts,
fee,
mixRing,
amount_keys,
index,
outSk,
rct_config,
hwdev,
salvium_data,
rct::sk2rct(x_change),
change_index,
key_yF
);
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));
+8 -1
View File
@@ -39,9 +39,11 @@
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
@@ -64,10 +66,11 @@ namespace cryptonote
uint8_t type;
crypto::public_key P_change;
crypto::public_key return_pubkey;
uint64_t origin_height;
};
//---------------------------------------------------------------
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_protocol_tx(const size_t height, transaction& tx, std::vector<protocol_data_entry>& protocol_data, const uint8_t hf_version);
//---------------------------------------------------------------
bool construct_miner_tx(size_t height, size_t median_weight, uint64_t already_generated_coins, size_t current_block_weight, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 999, uint8_t hard_fork_version = 1);
@@ -150,6 +153,7 @@ namespace cryptonote
FIELD(original)
VARINT_FIELD(amount)
FIELD(addr)
FIELD(asset_type)
FIELD(is_subaddress)
FIELD(is_integrated)
FIELD(is_change)
@@ -170,6 +174,9 @@ 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 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::string encrypt_pvk(const crypto::secret_key &pvk, const crypto::public_key &PK);
bool decrypt_pvk(const std::string &encrypted_data, const crypto::secret_key &SK, crypto::secret_key &pvk);
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);
+21 -14
View File
@@ -112,8 +112,8 @@ namespace cryptonote
uint64_t get_transaction_weight_limit(uint8_t version)
{
// from v8, limit a tx to 50% of the minimum block weight
if (version >= 8)
// from v2, limit a tx to 50% of the minimum block weight
if (version >= 2)
return get_min_block_weight(version) / 2 - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
else
return get_min_block_weight(version) - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE;
@@ -167,6 +167,15 @@ namespace cryptonote
return false;
}
// Reject ALL TXs except miner + protocol for v5
if (version == HF_VERSION_SHUTDOWN_USER_TXS) {
if (tx.type != cryptonote::transaction_type::MINER && tx.type != cryptonote::transaction_type::PROTOCOL) {
LOG_PRINT_L1("User TXs are not permitted for v" + std::to_string(HF_VERSION_SHUTDOWN_USER_TXS));
tvc.m_verifivation_failed = true;
return false;
}
}
if(!check_inputs_types_supported(tx))
{
tvc.m_verifivation_failed = true;
@@ -259,10 +268,10 @@ namespace cryptonote
tvc.m_invalid_output = true;
return false;
}
// Check the TX type
if (tx.type <= cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) {
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid type " << (uint8_t)tx.type);
if (!m_blockchain.check_tx_type_and_version(tx, tvc)) {
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid type " << (uint8_t)tx.type << " and/or version " << tx.version);
tvc.m_verifivation_failed = true;
return false;
}
@@ -1614,7 +1623,7 @@ namespace cryptonote
//---------------------------------------------------------------------------------
//---------------------------------------------------------------------------------
//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, oracle::pricing_record& pr, std::map<std::string, uint64_t>& circ_supply, std::vector<txpool_tx_meta_t>& protocol_metadata)
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)
{
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
@@ -1653,6 +1662,12 @@ namespace cryptonote
continue;
}
// SRCG: skip all user TXs for HF 5 - when the node restarts, it'll discard them fully in `tx_memory_pool::validate()`
if (version == HF_VERSION_SHUTDOWN_USER_TXS) {
LOG_PRINT_L2(" User TXs forbidden by consensus for HF 5 - skipping");
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))
@@ -1744,14 +1759,6 @@ 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;
+1 -4
View File
@@ -227,13 +227,10 @@ namespace cryptonote
* @param fee return-by-reference the total of fees from the included transactions
* @param expected_reward return-by-reference the total reward awarded to the miner finding this block, including transaction fees
* @param version hard fork version to use for consensus rules
* @param pr the current pricing record
* @param circ_cupply the circulating supply information for all asset types
* @param protocol_metadata the TX-specific data needed to create conversion outputs in the protocol TX (including converted amounts and refunds)
*
* @return true
*/
bool 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);
bool 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);
/**
* @brief get a list of all transactions in the pool
@@ -130,7 +130,7 @@ bool ver_rct_non_semantics_simple_cached
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions
// holds true in the future, enable the verification hash by modifying the `untested_tx`
// condition below.
const bool untested_tx = tx.version > 2 || tx.rct_signatures.type > rct::RCTTypeBulletproofPlus;
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeSalviumOne;
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
// Don't cache older (or newer) rctSig types
+15 -14
View File
@@ -40,15 +40,6 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "cn.block_queue"
namespace std {
static_assert(sizeof(size_t) <= sizeof(boost::uuids::uuid), "boost::uuids::uuid too small");
template<> struct hash<boost::uuids::uuid> {
std::size_t operator()(const boost::uuids::uuid &_v) const {
return reinterpret_cast<const std::size_t &>(_v);
}
};
}
namespace cryptonote
{
@@ -60,10 +51,10 @@ void block_queue::add_blocks(uint64_t height, std::vector<cryptonote::block_comp
blocks.insert(span(height, std::move(bcel), connection_id, addr, rate, size));
if (has_hashes)
{
for (const crypto::hash &h: hashes)
for (std::size_t i = 0; i < hashes.size(); ++i)
{
requested_hashes.insert(h);
have_blocks.insert(h);
requested_hashes.insert(hashes[i]);
have_blocks.emplace(hashes[i], height + i);
}
set_span_hashes(height, connection_id, hashes);
}
@@ -228,6 +219,16 @@ bool block_queue::have(const crypto::hash &hash) const
return have_blocks.find(hash) != have_blocks.end();
}
std::uint64_t block_queue::have_height(const crypto::hash &hash) const
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
const auto elem = have_blocks.find(hash);
if (elem == have_blocks.end())
return std::numeric_limits<std::uint64_t>::max();
return elem->second;
}
std::pair<uint64_t, uint64_t> block_queue::reserve_span(uint64_t first_block_height, uint64_t last_block_height, uint64_t max_blocks, const boost::uuids::uuid &connection_id, const epee::net_utils::network_address &addr, bool sync_pruned_blocks, uint32_t local_pruning_seed, uint32_t pruning_seed, uint64_t blockchain_height, const std::vector<std::pair<crypto::hash, uint64_t>> &block_hashes, boost::posix_time::ptime time)
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
@@ -472,7 +473,7 @@ bool block_queue::has_spans(const boost::uuids::uuid &connection_id) const
float block_queue::get_speed(const boost::uuids::uuid &connection_id) const
{
boost::unique_lock<boost::recursive_mutex> lock(mutex);
std::unordered_map<boost::uuids::uuid, float> speeds;
std::unordered_map<boost::uuids::uuid, float, boost::hash<boost::uuids::uuid>> speeds;
for (const auto &span: blocks)
{
if (span.blocks.empty())
@@ -480,7 +481,7 @@ float block_queue::get_speed(const boost::uuids::uuid &connection_id) const
// note that the average below does not average over the whole set, but over the
// previous pseudo average and the latest rate: this gives much more importance
// to the latest measurements, which is fine here
std::unordered_map<boost::uuids::uuid, float>::iterator i = speeds.find(span.connection_id);
const auto i = speeds.find(span.connection_id);
if (i == speeds.end())
speeds.insert(std::make_pair(span.connection_id, span.rate));
else
+2 -1
View File
@@ -98,6 +98,7 @@ namespace cryptonote
bool foreach(std::function<bool(const span&)> f) const;
bool requested(const crypto::hash &hash) const;
bool have(const crypto::hash &hash) const;
std::uint64_t have_height(const crypto::hash &hash) const;
private:
void erase_block(block_map::iterator j);
@@ -107,6 +108,6 @@ namespace cryptonote
block_map blocks;
mutable boost::recursive_mutex mutex;
std::unordered_set<crypto::hash> requested_hashes;
std::unordered_set<crypto::hash> have_blocks;
std::unordered_map<crypto::hash, std::uint64_t> have_blocks;
};
}
@@ -158,6 +158,7 @@ namespace cryptonote
bool should_ask_for_pruned_data(cryptonote_connection_context& context, uint64_t first_block_height, uint64_t nblocks, bool check_block_weights) const;
void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans);
void drop_connection_with_score(cryptonote_connection_context &context, unsigned int score, bool flush_all_spans);
void drop_connection(const boost::uuids::uuid&);
void drop_connections(const epee::net_utils::network_address address);
bool kick_idle_peers();
bool check_standby_peers();
@@ -35,6 +35,7 @@
// (may contain code and/or modifications by other developers)
// developer rfree: this code is caller of our new network code, and is modded; e.g. for rate limiting
#include <boost/optional/optional.hpp>
#include <list>
#include <ctime>
@@ -380,7 +381,7 @@ namespace cryptonote
if(m_core.have_block(hshd.top_id))
{
context.m_state = cryptonote_connection_context::state_normal;
context.set_state_normal();
if(is_inital && hshd.current_height >= target && target == m_core.get_current_blockchain_height())
on_connection_synchronized();
return true;
@@ -389,7 +390,7 @@ namespace cryptonote
// No chain synchronization over hidden networks (tor, i2p, etc.)
if(context.m_remote_address.get_zone() != epee::net_utils::zone::public_)
{
context.m_state = cryptonote_connection_context::state_normal;
context.set_state_normal();
return true;
}
@@ -430,7 +431,7 @@ namespace cryptonote
if (m_no_sync)
{
context.m_state = cryptonote_connection_context::state_normal;
context.set_state_normal();
return true;
}
@@ -1198,8 +1199,9 @@ namespace cryptonote
block_hashes.reserve(arg.blocks.size());
const boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
uint64_t start_height = std::numeric_limits<uint64_t>::max();
crypto::hash previous{};
cryptonote::block b;
for(const block_complete_entry& block_entry: arg.blocks)
for(std::size_t i = 0; i < arg.blocks.size(); ++i)
{
if (m_stopping)
{
@@ -1207,10 +1209,10 @@ namespace cryptonote
}
crypto::hash block_hash;
if(!parse_and_validate_block_from_blob(block_entry.block, b, block_hash))
if(!parse_and_validate_block_from_blob(arg.blocks[i].block, b, block_hash))
{
LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: "
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
<< epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
@@ -1218,14 +1220,25 @@ namespace cryptonote
if (b.miner_tx.vin.size() != 1 || b.miner_tx.vin.front().type() != typeid(txin_gen))
{
LOG_ERROR_CCONTEXT("sent wrong block: block: miner tx does not have exactly one txin_gen input"
<< epee::string_tools::buff_to_hex_nodelimer(block_entry.block) << ", dropping connection");
<< epee::string_tools::buff_to_hex_nodelimer(arg.blocks[i].block) << ", dropping connection");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
}
const auto this_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
if (context.get_expected_hash(this_height) != block_hash)
{
LOG_ERROR_CCONTEXT("Sent invalid chain");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
}
// if first block
if (start_height == std::numeric_limits<uint64_t>::max())
{
start_height = boost::get<txin_gen>(b.miner_tx.vin[0]).height;
start_height = this_height;
if (start_height > context.m_expect_height)
{
LOG_ERROR_CCONTEXT("sent block ahead of expected height, dropping connection");
@@ -1233,21 +1246,45 @@ namespace cryptonote
++m_sync_bad_spans_downloaded;
return 1;
}
if (this_height == 0 || context.get_expected_hash(this_height - 1) != b.prev_id)
{
LOG_ERROR_CCONTEXT("Sent invalid chain");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
}
}
else if (b.prev_id != previous)
{
LOG_ERROR_CCONTEXT("Sent invalid chain");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
}
previous = block_hash;
if (start_height + i != this_height)
{
LOG_ERROR_CCONTEXT("Sent invalid chain");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
}
auto req_it = context.m_requested_objects.find(block_hash);
if(req_it == context.m_requested_objects.end())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block))
<< " wasn't requested, dropping connection");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
}
if(b.tx_hashes.size() != block_entry.txs.size())
if(b.tx_hashes.size() != arg.blocks[i].txs.size())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(block_entry.block))
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection");
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epee::string_tools::pod_to_hex(get_blob_hash(arg.blocks[i].block))
<< ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << arg.blocks[i].txs.size() << ", dropping connection");
drop_connection(context, false, false);
++m_sync_bad_spans_downloaded;
return 1;
@@ -1465,6 +1502,14 @@ namespace cryptonote
bool parent_known = m_core.have_block(new_block.prev_id);
if (!parent_known)
{
const std::uint64_t confirmed_height = m_block_queue.have_height(new_block.prev_id);
if (confirmed_height != std::numeric_limits<std::uint64_t>::max() && confirmed_height + 1 != start_height)
{
MERROR(context << "Found incorrect height for " << new_block.prev_id << " provided by " << span_connection_id);
drop_connection(span_connection_id);
return 1;
}
// it could be:
// - later in the current chain
// - later in an alt chain
@@ -2093,7 +2138,6 @@ skip:
m_block_queue.flush_stale_spans(live_connections);
// if we don't need to get next span, and the block queue is full enough, wait a bit
bool start_from_current_chain = false;
if (!force_next_span)
{
do
@@ -2116,7 +2160,7 @@ skip:
return false;
}
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
context.m_state = cryptonote_connection_context::state_normal;
context.set_state_normal();
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
on_connection_synchronized();
return true;
@@ -2265,7 +2309,7 @@ skip:
return false;
}
MDEBUG(context << "Nothing to get from this peer, and it's not ahead of us, all done");
context.m_state = cryptonote_connection_context::state_normal;
context.set_state_normal();
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
on_connection_synchronized();
return true;
@@ -2378,7 +2422,7 @@ skip:
const uint64_t blockchain_height = m_core.get_current_blockchain_height();
if (std::max(blockchain_height, m_block_queue.get_next_needed_height(blockchain_height)) >= m_core.get_target_blockchain_height())
{
context.m_state = cryptonote_connection_context::state_normal;
context.set_state_normal();
MLOG_PEER_STATE("Nothing to do for now, switching to normal state");
return true;
}
@@ -2421,14 +2465,11 @@ skip:
m_core.get_short_chain_history(r.block_ids);
CHECK_AND_ASSERT_MES(!r.block_ids.empty(), false, "Short chain history is empty");
if (!start_from_current_chain)
// we'll want to start off from where we are on that peer, which may not be added yet
if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
{
// we'll want to start off from where we are on that peer, which may not be added yet
if (context.m_last_known_hash != crypto::null_hash && r.block_ids.front() != context.m_last_known_hash)
{
context.m_expect_height = std::numeric_limits<uint64_t>::max();
r.block_ids.push_front(context.m_last_known_hash);
}
context.m_expect_height = std::numeric_limits<uint64_t>::max();
r.block_ids.push_front(context.m_last_known_hash);
}
handler_request_blocks_history( r.block_ids ); // change the limit(?), sleep(?)
@@ -2441,7 +2482,7 @@ skip:
context.m_last_request_time = boost::posix_time::microsec_clock::universal_time();
context.m_expect_response = NOTIFY_RESPONSE_CHAIN_ENTRY::ID;
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size() << ", start_from_current_chain " << start_from_current_chain);
MLOG_P2P_MESSAGE("-->>NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << r.block_ids.size());
post_notify<NOTIFY_REQUEST_CHAIN>(r, context);
MLOG_PEER_STATE("requesting chain");
}else
@@ -2455,7 +2496,7 @@ skip:
<< "\r\nm_requested_objects.size()=" << context.m_requested_objects.size()
<< "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]");
context.m_state = cryptonote_connection_context::state_normal;
context.set_state_normal();
if (context.m_remote_blockchain_height >= m_core.get_target_blockchain_height())
{
if (m_core.get_current_blockchain_height() >= m_core.get_target_blockchain_height())
@@ -2628,11 +2669,14 @@ skip:
return 1;
}
context.m_expected_heights_start = arg.start_height;
context.m_expected_heights.clear();
context.m_expected_heights.reserve(arg.m_block_ids.size());
context.m_needed_objects.clear();
context.m_needed_objects.reserve(arg.m_block_ids.size());
uint64_t added = 0;
std::unordered_set<crypto::hash> blocks_found;
bool first = true;
bool expect_unknown = false;
for (size_t i = 0; i < arg.m_block_ids.size(); ++i)
{
@@ -2644,9 +2688,10 @@ skip:
}
int where;
const bool have_block = m_core.have_block_unlocked(arg.m_block_ids[i], &where);
if (first)
if (i == 0)
{
if (!have_block && !m_block_queue.requested(arg.m_block_ids[i]) && !m_block_queue.have(arg.m_block_ids[i]))
// our outgoing chainlist only has proven blocks (i.e. downloaded)
if (!have_block && m_block_queue.have_height(arg.m_block_ids[i]) != arg.start_height)
{
LOG_ERROR_CCONTEXT("First block hash is unknown, dropping connection");
drop_connection_with_score(context, 5, false);
@@ -2655,7 +2700,7 @@ skip:
if (!have_block)
expect_unknown = true;
}
if (!first)
if (0 < i)
{
// after the first, blocks may be known or unknown, but if they are known,
// they should be at the same height if on the main chain
@@ -2696,10 +2741,10 @@ skip:
expect_unknown = true;
}
const uint64_t block_weight = arg.m_block_weights.empty() ? 0 : arg.m_block_weights[i];
context.m_expected_heights.push_back(arg.m_block_ids[i]);
context.m_needed_objects.push_back(std::make_pair(arg.m_block_ids[i], block_weight));
if (++added == n_use_blocks)
break;
first = false;
}
context.m_last_response_height -= arg.m_block_ids.size() - n_use_blocks;
@@ -2908,6 +2953,16 @@ skip:
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
void t_cryptonote_protocol_handler<t_core>::drop_connection(const boost::uuids::uuid& id)
{
m_p2p->for_connection(id, [this](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
// This _could be_ outside of strand, so careful on actions
drop_connection(context, true, false);
return true;
});
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
void t_cryptonote_protocol_handler<t_core>::drop_connections(const epee::net_utils::network_address address)
{
MWARNING("dropping connections to " << address.str());
@@ -2924,6 +2979,7 @@ skip:
{
m_block_queue.flush_spans(id, true);
m_p2p->for_connection(id, [&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t f)->bool{
// This _could be_ outside of strand, so careful on actions
drop_connection(context, true, false);
return true;
});
+2 -1
View File
@@ -53,6 +53,7 @@ namespace cryptonote
BURN = 5,
STAKE = 6,
RETURN = 7,
MAX = 7
AUDIT = 8,
MAX = 8
};
}
+32 -19
View File
@@ -28,6 +28,8 @@
#include "levin_notify.h"
#include <boost/asio/dispatch.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/steady_timer.hpp>
#include <boost/system/system_error.hpp>
#include <boost/uuid/uuid_io.hpp>
@@ -221,7 +223,7 @@ namespace levin
`dispatch` is used heavily, which means "execute immediately in _this_
thread if the strand is not in use, otherwise queue the callback to be
executed immediately after the strand completes its current task".
`post` is used where deferred execution to an `asio::io_service::run`
`post` is used where deferred execution to an `asio::io_context::run`
thread is preferred.
The strand per "zone" is useful because the levin
@@ -238,7 +240,7 @@ namespace levin
//! A queue of levin messages for a noise i2p/tor link
struct noise_channel
{
explicit noise_channel(boost::asio::io_service& io_service)
explicit noise_channel(boost::asio::io_context& io_service)
: active(nullptr),
queue(),
strand(io_service),
@@ -246,7 +248,7 @@ namespace levin
connection(boost::uuids::nil_uuid())
{}
// `asio::io_service::strand` cannot be copied or moved
// `asio::io_context::strand` cannot be copied or moved
noise_channel(const noise_channel&) = delete;
noise_channel& operator=(const noise_channel&) = delete;
@@ -254,7 +256,7 @@ namespace levin
epee::byte_slice active;
std::deque<epee::byte_slice> queue;
boost::asio::io_service::strand strand;
boost::asio::io_context::strand strand;
boost::asio::steady_timer next_noise;
boost::uuids::uuid connection;
};
@@ -264,7 +266,7 @@ namespace levin
{
struct zone
{
explicit zone(boost::asio::io_service& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs)
explicit zone(boost::asio::io_context& io_service, std::shared_ptr<connections> p2p, epee::byte_slice noise_in, epee::net_utils::zone zone, bool pad_txs)
: p2p(std::move(p2p)),
noise(std::move(noise_in)),
next_epoch(io_service),
@@ -286,7 +288,7 @@ namespace levin
const epee::byte_slice noise; //!< `!empty()` means zone is using noise channels
boost::asio::steady_timer next_epoch;
boost::asio::steady_timer flush_txs;
boost::asio::io_service::strand strand;
boost::asio::io_context::strand strand;
struct context_t {
std::vector<cryptonote::blobdata> fluff_txs;
std::chrono::steady_clock::time_point flush_time;
@@ -396,6 +398,8 @@ namespace levin
for (auto& connection : connections)
{
std::sort(connection.first.begin(), connection.first.end()); // don't leak receive order
connection.first.erase(std::unique(connection.first.begin(), connection.first.end()),
connection.first.end());
make_payload_send_txs(*zone_->p2p, std::move(connection.first), connection.second, zone_->pad_txs, true);
}
@@ -452,7 +456,7 @@ namespace levin
if (next_flush == std::chrono::steady_clock::time_point::max())
MWARNING("Unable to send transaction(s), no available connections");
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expires_at())
else if (!zone->flush_callbacks || next_flush < zone->flush_txs.expiry())
fluff_flush::queue(std::move(zone), next_flush);
}
};
@@ -513,7 +517,7 @@ namespace levin
for (auto id = zone->map.begin(); id != zone->map.end(); ++id)
{
const std::size_t i = id - zone->map.begin();
zone->channels[i].strand.post(update_channel{zone, i, *id});
boost::asio::post(zone->channels[i].strand, update_channel{zone, i, *id});
}
}
@@ -672,7 +676,7 @@ namespace levin
MWARNING("Unable to send transaction(s) to " << epee::net_utils::zone_to_string(zone_->nzone) <<
" - no suitable outbound connections at height " << height);
zone_->strand.post(update_channels{zone_, std::move(connections)});
boost::asio::post(zone_->strand, update_channels{zone_, std::move(connections)});
}
}
@@ -702,7 +706,8 @@ namespace levin
const bool fluffing = crypto::rand_idx(unsigned(100)) < CRYPTONOTE_DANDELIONPP_FLUFF_PROBABILITY;
const auto start = std::chrono::steady_clock::now();
auto connections = get_out_connections(*(zone_->p2p), core_);
zone_->strand.dispatch(
boost::asio::dispatch(
zone_->strand,
change_channels{zone_, net::dandelionpp::connection_map{std::move(connections), count_}, fluffing}
);
@@ -713,7 +718,7 @@ namespace levin
};
} // anonymous
notify::notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core)
notify::notify(boost::asio::io_context& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, const bool pad_txs, i_core_events& core)
: zone_(std::make_shared<detail::zone>(service, std::move(p2p), std::move(noise), zone, pad_txs))
, core_(std::addressof(core))
{
@@ -741,9 +746,14 @@ namespace levin
notify::status notify::get_status() const noexcept
{
if (!zone_)
return {false, false};
return {false, false, false};
return {!zone_->noise.empty(), CRYPTONOTE_NOISE_CHANNELS <= zone_->connection_count};
// `connection_count` is only set when `!noise.empty()`.
const std::size_t connection_count = zone_->connection_count;
bool has_outgoing = connection_count;
if (zone_->noise.empty())
has_outgoing = zone_->p2p->get_out_connections_count();
return {!zone_->noise.empty(), CRYPTONOTE_NOISE_CHANNELS <= connection_count, has_outgoing};
}
void notify::new_out_connection()
@@ -751,7 +761,8 @@ namespace levin
if (!zone_ || zone_->noise.empty() || CRYPTONOTE_NOISE_CHANNELS <= zone_->connection_count)
return;
zone_->strand.dispatch(
boost::asio::dispatch(
zone_->strand,
update_channels{zone_, get_out_connections(*(zone_->p2p), core_)}
);
}
@@ -762,7 +773,7 @@ namespace levin
return;
auto& zone = zone_;
zone_->strand.dispatch([zone, id, is_income]{
boost::asio::dispatch(zone_->strand, [zone, id, is_income] {
zone->contexts[id] = {
.fluff_txs = {},
.flush_time = std::chrono::steady_clock::time_point::max(),
@@ -777,7 +788,7 @@ namespace levin
return;
auto& zone = zone_;
zone_->strand.dispatch([zone, id]{
boost::asio::dispatch(zone_->strand, [zone, id]{
zone->contexts.erase(id);
});
}
@@ -852,7 +863,8 @@ namespace levin
for (std::size_t channel = 0; channel < zone_->channels.size(); ++channel)
{
zone_->channels[channel].strand.dispatch(
boost::asio::dispatch(
zone_->channels[channel].strand,
queue_covert_notify{zone_, message.clone(), channel}
);
}
@@ -871,7 +883,8 @@ namespace levin
if (zone_->nzone == epee::net_utils::zone::public_)
{
// this will change a local/forward tx to stem or fluff ...
zone_->strand.dispatch(
boost::asio::dispatch(
zone_->strand,
dandelionpp_notify{zone_, core_, std::move(txs), source, tx_relay}
);
break;
@@ -884,7 +897,7 @@ namespace levin
ipv4/6. Marking it as "fluff" here will make the tx immediately
visible externally from this node, which is not desired. */
core_->on_transactions_relayed(epee::to_span(txs), tx_relay);
zone_->strand.dispatch(fluff_notify{zone_, std::move(txs), source});
boost::asio::dispatch(zone_->strand, fluff_notify{zone_, std::move(txs), source});
break;
}
}
+4 -3
View File
@@ -28,7 +28,7 @@
#pragma once
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/uuid/uuid.hpp>
#include <memory>
#include <vector>
@@ -75,7 +75,8 @@ namespace levin
struct status
{
bool has_noise;
bool connections_filled;
bool connections_filled; //!< True when has zone has `CRYPTONOTE_NOISE_CHANNELS` outgoing noise channels
bool has_outgoing; //!< True when zone has outgoing connections
};
//! Construct an instance that cannot notify.
@@ -85,7 +86,7 @@ namespace levin
{}
//! Construct an instance with available notification `zones`.
explicit notify(boost::asio::io_service& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core);
explicit notify(boost::asio::io_context& service, std::shared_ptr<connections> p2p, epee::byte_slice noise, epee::net_utils::zone zone, bool pad_txs, i_core_events& core);
notify(const notify&) = delete;
notify(notify&&) = default;
+10
View File
@@ -696,6 +696,16 @@ bool t_command_parser_executor::ban(const std::vector<std::string>& args)
std::ifstream ifs(ban_list_path.string());
for (std::string line; std::getline(ifs, line); )
{
// ignore comments after '#' character
const size_t pound_idx = line.find('#');
if (pound_idx != std::string::npos)
line.resize(pound_idx);
// trim whitespace and ignore empty lines
boost::trim(line);
if (line.empty())
continue;
auto subnet = net::get_ipv4_subnet_address(line);
if (subnet)
{
+6 -7
View File
@@ -83,7 +83,7 @@ uint16_t parse_public_rpc_port(const po::variables_map &vm)
}
uint16_t rpc_port;
if (!string_tools::get_xtype_from_string(rpc_port, rpc_port_str))
if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str))
{
throw std::runtime_error("invalid RPC port " + rpc_port_str);
}
@@ -141,9 +141,9 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
miner_key_file << "Miner account address:" << std::endl;
miner_key_file << cryptonote::get_account_address_as_str((network_type)nettype, false, miner_acc1.get_keys().m_account_address);
miner_key_file << std::endl<< "Miner spend secret key:" << std::endl;
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(miner_acc1.get_keys().m_spend_secret_key));
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_spend_secret_key))));
miner_key_file << std::endl << "Miner view secret key:" << std::endl;
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(miner_acc1.get_keys().m_view_secret_key));
epee::to_hex::formatted(miner_key_file, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_view_secret_key))));
miner_key_file << std::endl << std::endl;
miner_key_file.close();
@@ -153,13 +153,13 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
std::cout << "Object:" << std::endl;
std::cout << obj_to_json_str(tx_genesis) << std::endl << std::endl;
std::cout << "Gennerating miner wallet..." << std::endl;
std::cout << "Generating miner wallet..." << std::endl;
std::cout << "Miner account address:" << std::endl;
std::cout << cryptonote::get_account_address_as_str((network_type)nettype, false, miner_acc1.get_keys().m_account_address);
std::cout << std::endl << "Miner spend secret key:" << std::endl;
epee::to_hex::formatted(std::cout, epee::as_byte_span(miner_acc1.get_keys().m_spend_secret_key));
epee::to_hex::formatted(std::cout, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_spend_secret_key))));
std::cout << std::endl << "Miner view secret key:" << std::endl;
epee::to_hex::formatted(std::cout, epee::as_byte_span(miner_acc1.get_keys().m_view_secret_key));
epee::to_hex::formatted(std::cout, epee::as_byte_span(unwrap(unwrap(miner_acc1.get_keys().m_view_secret_key))));
std::cout << std::endl << std::endl;
std::stringstream ss;
@@ -168,7 +168,6 @@ void print_genesis_tx_hex(const cryptonote::network_type nettype) {
std::string tx_hex = ss.str();
std::cout << "Insert this line into your coin configuration file: " << std::endl;
std::cout << "std::string const GENESIS_TX = \"" << epee::string_tools::buff_to_hex_nodelimer(tx_hex) << "\";" << std::endl;
return;
}
+1 -1
View File
@@ -1064,7 +1064,7 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash,
cryptonote::blobdata blob;
std::string source = as_hex.empty() ? pruned_as_hex + prunable_as_hex : as_hex;
bool pruned = !pruned_as_hex.empty() && prunable_as_hex.empty();
if (!string_tools::parse_hexstr_to_binbuff(source, blob))
if (!epee::string_tools::parse_hexstr_to_binbuff(source, blob))
{
tools::fail_msg_writer() << "Failed to parse tx to get json format";
}
+6 -4
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2017-2023, The Monero Project
// Copyright (c) 2017-2024, The Monero Project
//
// All rights reserved.
//
@@ -317,13 +317,15 @@ namespace hw {
{
// sending change to yourself; derivation = a*R
r = generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation);
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")");
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", <viewkey>)");
}
else
{
// sending to the recipient; derivation = r*A (or s*C in the subaddress scheme)
r = generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation);
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << (dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key) << ")");
const crypto::secret_key &tx_privkey{dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key};
r = generate_key_derivation(dst_entr.addr.m_view_public_key, tx_privkey, derivation);
CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation("
<< dst_entr.addr.m_view_public_key << ", " << crypto::secret_key_explicit_print_ref{tx_privkey} << ")");
}
if (need_additional_txkeys)
+4 -3
View File
@@ -528,6 +528,7 @@ namespace hw {
{0x2c97, 0x0004, 0, 0xffa0},
{0x2c97, 0x0005, 0, 0xffa0},
{0x2c97, 0x0006, 0, 0xffa0},
{0x2c97, 0x0007, 0, 0xffa0},
};
bool device_ledger::connect(void) {
@@ -1929,7 +1930,7 @@ namespace hw {
// ====== Aout, Bout, AKout, C, v, k ======
kv_offset = data_offset;
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus) {
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs) {
C_offset = kv_offset+ (8)*outputs_size;
} else {
C_offset = kv_offset+ (32+32)*outputs_size;
@@ -1946,7 +1947,7 @@ namespace hw {
offset = set_command_header(INS_VALIDATE, 0x02, i+1);
//options
this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ;
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus)?0x02:0x00;
this->buffer_send[offset] |= (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs)?0x02:0x00;
offset += 1;
//is_subaddress
this->buffer_send[offset] = outKeys.is_subaddress;
@@ -1967,7 +1968,7 @@ namespace hw {
memmove(this->buffer_send+offset, data+C_offset,32);
offset += 32;
C_offset += 32;
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus) {
if (type==rct::RCTTypeBulletproof2 || type==rct::RCTTypeCLSAG || type==rct::RCTTypeBulletproofPlus || type==rct::RCTTypeFullProofs) {
//k
memset(this->buffer_send+offset, 0, 32);
offset += 32;
+1 -3
View File
@@ -34,7 +34,6 @@
#include <algorithm>
#include <functional>
#include <boost/endian/conversion.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/format.hpp>
@@ -614,8 +613,7 @@ namespace trezor{
}
udp::resolver resolver(m_io_service);
udp::resolver::query query(udp::v4(), m_device_host, std::to_string(m_device_port));
m_endpoint = *resolver.resolve(query);
m_endpoint = *resolver.resolve(udp::v4(), m_device_host, std::to_string(m_device_port)).begin();
m_socket.reset(new udp::socket(m_io_service));
m_socket->open(udp::v4());
+1 -1
View File
@@ -244,7 +244,7 @@ namespace trezor {
int m_device_port;
std::unique_ptr<udp::socket> m_socket;
boost::asio::io_service m_io_service;
boost::asio::io_context m_io_service;
boost::asio::deadline_timer m_deadline;
udp::endpoint m_endpoint;
};
+46 -4
View File
@@ -35,8 +35,29 @@ const hardfork_t mainnet_hard_forks[] = {
// version 1 from the start of the blockchain
{ 1, 1, 0, 1341378000 },
// version 2 starts from block 1000, which is on or around the 20th of March, 2016. Fork time finalised on 2015-09-20. No fork voting occurs for the v2 fork.
//{ 2, 1000, 0, 1442763710 },
// version 2 starts from block 89800, which is on or around the 4th of November, 2024. Fork time finalised on 2024-10-21. No fork voting occurs for the v2 fork.
{ 2, 89800, 0, 1729518000 },
// version 3 starts from block 121100, which is on or around the 19th of December, 2024. Fork time finalised on 2024-12-18. No fork voting occurs for the v3 fork.
{ 3, 121100, 0, 1734516900 },
// version 4 starts from block 121100, which is on or around the 20th of December, 2024. Fork time finalised on 2024-12-19. No fork voting occurs for the v4 fork.
{ 4, 121800, 0, 1734607000 },
// version 5 starts from block 136100, which is on or around the 9th of January, 2025. Fork time finalised on 2025-01-08. No fork voting occurs for the v5 fork.
{ 5, 136100, 0, 1736265945 },
// version 6 starts from block 154750, which is on or around the 4th of February, 2025. Fork time finalised on 2025-01-31. No fork voting occurs for the v6 fork.
{ 6, 154750, 0, 1738336000 },
// version 7 starts from block 161900, which is on or around the 14th of February, 2025. Fork time finalised on 2025-02-04. No fork voting occurs for the v7 fork.
{ 7, 161900, 0, 1739264400 },
// version 8 starts from block 172000, which is on or around the 28th of February, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v8 fork.
{ 8, 172000, 0, 1740390000 },
// version 9 starts from block 179200, which is on or around the 10th of March, 2025. Fork time finalised on 2025-02-24. No fork voting occurs for the v9 fork.
{ 9, 179200, 0, 1740393800 },
};
const size_t num_mainnet_hard_forks = sizeof(mainnet_hard_forks) / sizeof(mainnet_hard_forks[0]);
const uint64_t mainnet_hard_fork_version_1_till = ((uint64_t)-1);
@@ -45,8 +66,29 @@ const hardfork_t testnet_hard_forks[] = {
// version 1 from the start of the blockchain
{ 1, 1, 0, 1341378000 },
// version 2 starts from block 1000, which is on or around the 23rd of November, 2015. Fork time finalised on 2015-11-20. No fork voting occurs for the v2 fork.
//{ 2, 1000, 0, 1445355000 },
// version 2 starts from block 250
{ 2, 250, 0, 1445355000 },
// version 3 starts from block 500
{ 3, 500, 0, 1729518000 },
// version 4 (full proofs) starts from block 600
{ 4, 600, 0, 1734607000 },
// version 5 (TX shutdown) starts from block 800
{ 5, 800, 0, 1734607005 },
// version 6 (audit 1) starts from block 815
{ 6, 815, 0, 1734608000 },
// version 7 (audit 1 pause, blacklist controlling payouts) starts from block 900
{ 7, 900, 0, 1739264400 },
// version 8 (audit 1 resume) starts from block 950
{ 8, 950, 0, 1739270000 },
// version 9 (audit 1 complete, whitelist controlling payouts) starts from block 1000
{ 9, 1000, 0, 1739280000 },
};
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
+1
View File
@@ -133,6 +133,7 @@ namespace lmdb
//! \pre `!is_end()` \return Current key
K get_key() const noexcept
{
static_assert(std::is_trivially_copyable<K>(), "key is not memcpy safe");
assert(!is_end());
K out;
std::memcpy(std::addressof(out), key.data(), sizeof(out));
+1 -1
View File
@@ -55,7 +55,7 @@ namespace lmdb
static expect<F> get_value(MDB_val value) noexcept
{
static_assert(std::is_same<U, V>(), "bad MONERO_FIELD?");
static_assert(std::is_pod<F>(), "F must be POD");
static_assert(std::is_trivially_copyable<F>(), "F must be memcpy safe");
static_assert(sizeof(F) + offset <= sizeof(U), "bad field type and/or offset");
if (value.mv_size != sizeof(U))
+3 -2
View File
@@ -111,6 +111,7 @@ namespace lmdb
template<typename T, std::size_t offset = 0>
inline int less(MDB_val const* left, MDB_val const* right) noexcept
{
static_assert(std::is_trivially_copyable<T>(), "memcpy will not work");
if (!left || !right || left->mv_size < sizeof(T) + offset || right->mv_size < sizeof(T) + offset)
{
assert("invalid use of custom comparison" == 0);
@@ -127,7 +128,7 @@ namespace lmdb
/*!
A LMDB comparison function that uses `std::memcmp`.
\toaram T is `!epee::has_padding`
\toaram T has standard layout and an alignment of 1
\tparam offset to `T` within the value.
\return The result of `std::memcmp` over the value.
@@ -135,7 +136,7 @@ namespace lmdb
template<typename T, std::size_t offset = 0>
inline int compare(MDB_val const* left, MDB_val const* right) noexcept
{
static_assert(!epee::has_padding<T>(), "memcmp will not work");
static_assert(std::is_standard_layout<T>() && alignof(T) == 1, "memcmp will not work");
if (!left || !right || left->mv_size < sizeof(T) + offset || right->mv_size < sizeof(T) + offset)
{
assert("invalid use of custom comparison" == 0);

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