1
0
Fork 0
forked from lthn/blockchain

Merge branch 'develop' into cake

This commit is contained in:
cryptozoidberg 2024-02-08 16:03:13 +04:00
commit ecf1a7d487
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
87 changed files with 7093 additions and 580 deletions

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.5)
PROJECT(Zano)
@ -194,8 +194,8 @@ else()
endif()
# If BOOST_ROOT is set, ignore system-wide Boost
if(DEFINED ENV{BOOST_ROOT})
# always use local Boost installation rather than the system-wide (unless ZANO_USE_SYSTEM_BOOST is defined for some reason, which is not recommended)
if(NOT DEFINED ENV{ZANO_USE_SYSTEM_BOOST})
set(Boost_NO_SYSTEM_PATHS ON)
endif()
@ -221,6 +221,8 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(Boost_LIBRARY_DIRS "${Boost_LIBRARY_DIRS}/${CMAKE_ANDROID_ARCH_ABI}/")
set(Boost_LIBRARIES "${Boost_LIBRARY_DIRS}libboost_system.a;${Boost_LIBRARY_DIRS}libboost_filesystem.a;${Boost_LIBRARY_DIRS}libboost_thread.a;${Boost_LIBRARY_DIRS}libboost_timer.a;${Boost_LIBRARY_DIRS}libboost_date_time.a;${Boost_LIBRARY_DIRS}libboost_chrono.a;${Boost_LIBRARY_DIRS}libboost_regex.a;${Boost_LIBRARY_DIRS}libboost_serialization.a;${Boost_LIBRARY_DIRS}libboost_atomic.a;${Boost_LIBRARY_DIRS}libboost_program_options.a")
elseif(APPLE)
find_package(Boost 1.71 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
else()
find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
endif()
@ -244,7 +246,7 @@ elseif(NOT MSVC)
endif()
if(BUILD_GUI)
cmake_minimum_required(VERSION 2.8.11)
cmake_minimum_required(VERSION 3.5)
find_package(Qt5Widgets REQUIRED)
endif()

View file

@ -42,18 +42,25 @@ Recommended OS versions: Ubuntu 20.04, 22.04 LTS.
sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev mesa-common-dev libglu1-mesa-dev
2. Download and build Boost\
(Assuming you have cloned Zano into the 'zano' folder. If you used a different location for Zano, edit line 4 accordingly.)
2. Clone Zano into a local folder\
(If for some reason you need to use alternative Zano branch, change 'master' to the required branch name.)
git clone --recursive https://github.com/hyle-team/zano.git -b master
In the following steps we assume that you cloned Zano into '~/zano' folder in your home directory.
3. Download and build Boost\
(Assuming you have cloned Zano into the 'zano' folder. If you used a different location for Zano, **edit line 4** accordingly.)
curl -OL https://boostorg.jfrog.io/artifactory/main/release/1.70.0/source/boost_1_70_0.tar.bz2
echo "430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 boost_1_70_0.tar.bz2" | shasum -c && tar -xjf boost_1_70_0.tar.bz2
rm boost_1_70_0.tar.bz2 && cd boost_1_70_0
patch -p0 < ../zano/utils/boost_1.70_gcc_8.patch || cd ..
./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer,log
./b2
./b2 && cd ..
Make sure that you see "The Boost C++ Libraries were successfully built!" message at the end.
3. Install Qt\
4. Install Qt\
(*GUI version only, skip this step if you're building server version*)
[*GUI version*]
@ -64,18 +71,19 @@ Recommended OS versions: Ubuntu 20.04, 22.04 LTS.
Then follow the instructions in Wizard. Don't forget to tick the WebEngine module checkbox!
4. Install OpenSSL
5. Install OpenSSL
We recommend installing OpenSSL v1.1.1w locally unless you would like to use the same version system-wide. Adjust the local path `/home/user/openssl` in the commands below according to your needs.
We recommend installing OpenSSL v1.1.1w locally unless you would like to use the same version system-wide.\
(Assuming that `$HOME` environment variable is set to your home directory. Otherwise, edit line 4 accordingly.)
curl -OL https://www.openssl.org/source/openssl-1.1.1w.tar.gz
echo "cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8 openssl-1.1.1w.tar.gz" | shasum -c && tar xaf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w/
./config --prefix=/home/user/openssl --openssldir=/home/user/openssl shared zlib
make && make test && make install
./config --prefix=$HOME/openssl --openssldir=$HOME/openssl shared zlib
make && make test && make install && cd ..
5. Set environment variables properly\
6. [*OPTIONAL*] Set global environment variables for convenient use\
For instance, by adding the following lines to `~/.bashrc`
[*server version*]
@ -90,18 +98,27 @@ For instance, by adding the following lines to `~/.bashrc`
export OPENSSL_ROOT_DIR=/home/user/openssl
export QT_PREFIX_PATH=/home/user/Qt5.11.2/5.11.2/gcc_64
Make sure you've restarted your terminal session (by reopening the terminal window or reconnecting the server) to apply these changes.
6. Build the binaries
1. Build daemon and simplewallet:
cd zano/ && make -j1
or
**NOTICE: Please edit the lines above according to your actual paths.**
**NOTICE 2:** Make sure you've restarted your terminal session (by reopening the terminal window or reconnecting the server) to apply these changes.
8. Build the binaries
1. If you skipped step 6 and did not set the environment variables:
cd zano && mkdir build && cd build
BOOST_ROOT=$HOME/boost_1_70_0 OPENSSL_ROOT_DIR=$HOME/openssl cmake ..
make -j1 daemon simplewallet
2. If you set the variables in step 6:
cd zano && mkdir build && cd build
cmake ..
make -j1 daemon simplewallet
or simply:
cd zano && make -j1
**NOTICE**: If you are building on a machine with a relatively high amount of RAM or with the proper setting of virtual memory, then you can use `-j2` or `-j` option to speed up the building process. Use with caution.
**NOTICE 2**: If you'd like to build binaries for the testnet, use `cmake -D TESTNET=TRUE ..` instead of `cmake ..` .
@ -111,12 +128,12 @@ For instance, by adding the following lines to `~/.bashrc`
cd zano
utils/build_script_linux.sh
7. Look for the binaries in `build` folder
Look for the binaries in `build` folder
<br />
### Windows
Recommended OS version: Windows 7 x64.
Recommended OS version: Windows 7 x64, Windows 11 x64.
1. Install required prerequisites (Boost, Qt, CMake, OpenSSL).
2. Edit paths in `utils/configure_local_paths.cmd`.
3. Run one of `utils/configure_win64_msvsNNNN_gui.cmd` according to your MSVC version.

View file

@ -274,6 +274,21 @@ namespace misc_utils
}
}
uint64_t get_avg() const
{
CRITICAL_REGION_LOCAL(m_lock);
if (!queued_items.size())
return 0;
uint64_t summ = 0;
for (const auto& item : queued_items)
{
summ += *item.first;
}
return summ / queued_items.size();
}
template<typename key_t, typename associated_data_t>
friend std::ostream & operator<< (std::ostream &out, median_helper<key_t, associated_data_t> const &mh);
}; // class median_helper
@ -292,26 +307,25 @@ namespace misc_utils
/************************************************************************/
/* */
/************************************************************************/
template<class type_vec_type>
type_vec_type median(std::vector<type_vec_type> &v)
template<typename container_t>
typename container_t::value_type median(container_t &v)
{
//CRITICAL_REGION_LOCAL(m_lock);
typename container_t::value_type median{};
if(v.empty())
return boost::value_initialized<type_vec_type>();
return median;
if(v.size() == 1)
return v[0];
size_t n = (v.size()) / 2;
std::sort(v.begin(), v.end());
//nth_element(v.begin(), v.begin()+n-1, v.end());
if(v.size()%2)
{//1, 3, 5...
return v[n];
}else
{//2, 4, 6...
return (v[n-1] + v[n])/2;
auto median_it = v.begin() + v.size() / 2;
std::nth_element(v.begin(), median_it, v.end());
median = *median_it;
if (v.size() % 2 == 0)
{
auto max_it = std::max_element(v.begin(), median_it); // it's garanteed that after nth_element() the necessary element is in this interval
median = (median + *max_it) / 2; // average of [size/2-1] and [size/2] elements
}
return median;
}
/************************************************************************/

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2023 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -115,27 +115,6 @@ namespace crypto
END_BOOST_SERIALIZATION()
};
struct CLSAG_GGXG_signature_serialized : public CLSAG_GGXG_signature
{
BEGIN_SERIALIZE_OBJECT()
FIELD(c)
FIELD((std::vector<scalar_t>&)(r_g))
FIELD((std::vector<scalar_t>&)(r_x))
FIELD(K1)
FIELD(K2)
FIELD(K3)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_g))
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_x))
BOOST_SERIALIZE(K1)
BOOST_SERIALIZE(K2)
BOOST_SERIALIZE(K3)
END_BOOST_SERIALIZATION()
};
struct CLSAG_GGXXG_signature_serialized : public CLSAG_GGXXG_signature
{
BEGIN_SERIALIZE_OBJECT()

View file

@ -24,6 +24,7 @@
#define API_RETURN_CODE_WALLET_WRONG_ID "WALLET_WRONG_ID"
#define API_RETURN_CODE_WALLET_WATCH_ONLY_NOT_SUPPORTED "WALLET_WATCH_ONLY_NOT_SUPPORTED"
#define API_RETURN_CODE_WALLET_AUDITABLE_NOT_SUPPORTED "WALLET_AUDITABLE_NOT_SUPPORTED"
#define API_RETURN_CODE_WALLET_FEE_TOO_LOW "API_RETURN_CODE_WALLET_FEE_TOO_LOW"
#define API_RETURN_CODE_FILE_NOT_FOUND "FILE_NOT_FOUND"
#define API_RETURN_CODE_ALREADY_EXISTS "ALREADY_EXISTS"
#define API_RETURN_CODE_CANCELED "CANCELED"
@ -42,4 +43,4 @@
#define API_RETURN_CODE_TX_REJECTED "TX_REJECTED"
#define API_RETURN_CODE_HTLC_ORIGIN_HASH_MISSMATCHED "HTLC_ORIGIN_HASH_MISSMATCHED"
#define API_RETURN_CODE_WRAP "WRAP"
#define API_RETURN_CODE_MISSING_ZC_INPUTS "MISSING_ZC_INPUTS"
#define API_RETURN_CODE_MISSING_ZC_INPUTS "MISSING_ZC_INPUTS"

View file

@ -21,8 +21,8 @@ namespace tools
};
#ifndef TESTNET
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2200000.pak", "c3bd64c62495c3f266759750952519f13f32fc161b59547beaa8202b6e26d516", 2628767033, 5100195840 };
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2200000.pak", "fcbf0ab3b23836e1a51fa675e719900fb94110cfb74790b3323cebce7fb9f5bd", 3426025872, 4954472448 };
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2390000.pak", "ffc8d2220a4d8b3fba51073a422cbb6139c60858469ea086623f9d16329eb5b4", 2767268964, 5368627200 };
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2390000.pak", "7e58951bc523eb12e0ec07171bc67b3f96bad4d5454dd2da56f642a872e230d3", 3618283035, 5156397056 };
#else
static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 };
static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 };

View file

@ -407,8 +407,11 @@ bool generate_genesis(const std::string& path_config, uint64_t premine_split_amo
ss.str("");
ss.clear();
const account_public_address dummy_address = AUTO_VAL_INIT(dummy_address);
std::cout << ENDL << "PROOF PHRASE: " << gcp.proof_string << ENDL;
// construct_miner_tx(0, 0, 0, 0, 0, destinations, bl.miner_tx, TRANSACTION_VERSION_PRE_HF4, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS); <-- temporarily commented out; this overload needs to be re-implemented -- sowle
uint64_t block_reward_without_fee = 0;
construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS, false, pos_entry(), nullptr, nullptr, destinations);
currency::blobdata txb = tx_to_blob(bl.miner_tx);
//self validate block

View file

@ -1,9 +1,10 @@
// Copyright (c) 2022-2023 Zano Project
// Copyright (c) 2022-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2022-2024 Zano Project
// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// This file contains implementation of CLSAG (s.a. https://eprint.iacr.org/2019/654.pdf by Goodel at el)
// This file contains implementation of the original d-CLSAG (s.a. https://eprint.iacr.org/2019/654.pdf by Goodel at el)
// and the extended d/v-CLSAG version (s.a. https://github.com/hyle-team/docs/blob/master/zano/dv-CLSAG-extension/ by sowle)
//
#include "clsag.h"
//#include "misc_log_ex.h"
@ -51,6 +52,7 @@ namespace crypto
}
hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment);
hsc.add_key_image(ki);
hsc.add_pub_key(sig.K1);
hash input_hash = hsc.calc_hash_no_reduce();
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_LAYER_0);
@ -87,10 +89,7 @@ namespace crypto
hsc.add_point(alpha * ki_base);
scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1}
sig.r.clear();
sig.r.reserve(ring_size);
for(size_t i = 0; i < ring_size; ++i)
sig.r.emplace_back(scalar_t::random());
sig.r.resize_and_make_random(ring_size);
for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size)
{
@ -137,6 +136,7 @@ namespace crypto
}
hsc.add_pub_key(pseudo_out_amount_commitment);
hsc.add_key_image(ki);
hsc.add_pub_key(sig.K1);
hash input_hash = hsc.calc_hash_no_reduce();
hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_LAYER_0);
@ -203,8 +203,6 @@ namespace crypto
CRYPTO_CHECK_AND_THROW_MES((secret_0_xp * c_point_G).to_public_key() == ring[secret_index].stealth_address, "secret_0_xp mismatch");
CRYPTO_CHECK_AND_THROW_MES( secret_1_f * c_point_G == 8 * point_t(ring[secret_index].amount_commitment) - pseudo_out_amount_commitment, "secret_1_f mismatch");
CRYPTO_CHECK_AND_THROW_MES( secret_2_t * c_point_X == 8 * point_t(ring[secret_index].blinded_asset_id) - pseudo_out_blinded_asset_id, "secret_2_t mismatch");
//CRYPTO_CHECK_AND_THROW_MES( secret_3_q * c_point_G == 8 * point_t(ring[secret_index].concealing_point), "");
//CRYPTO_CHECK_AND_THROW_MES( secret_4_x * c_point_X == extended_amount_commitment - 8 * point_t(ring[secret_index].amount_commitment) - 8 * point_t(ring[secret_index].concealing_point), "");
#endif
point_t K1_div8 = (c_scalar_1div8 * secret_1_f) * ki_base;
@ -217,16 +215,6 @@ namespace crypto
point_t K2 = K2_div8;
K2.modify_mul8();
//point_t K3_div8 = (c_scalar_1div8 * secret_3_q) * ki_base;
//K3_div8.to_public_key(sig.K3);
//point_t K3 = K3_div8;
//K3.modify_mul8();
//point_t K4_div8 = (c_scalar_1div8 * secret_4_x) * ki_base;
//K4_div8.to_public_key(sig.K4);
//point_t K4 = K4_div8;
//K4.modify_mul8();
// calculate aggregation coefficients
hash_helper_t::hs_t hsc(4 + 3 * ring_size);
hsc.add_scalar(m);
@ -240,6 +228,8 @@ namespace crypto
hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment);
hsc.add_point(c_scalar_1div8 * pseudo_out_blinded_asset_id);
hsc.add_key_image(ki);
hsc.add_pub_key(sig.K1);
hsc.add_pub_key(sig.K2);
hash input_hash = hsc.calc_hash_no_reduce();
DBG_VAL_PRINT(input_hash);
@ -259,11 +249,6 @@ namespace crypto
scalar_t agg_coeff_2 = hsc.calc_hash();
DBG_VAL_PRINT(agg_coeff_2);
//hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_LAYER_3);
//hsc.add_hash(input_hash);
//scalar_t agg_coeff_3 = hsc.calc_hash();
//DBG_VAL_PRINT(agg_coeff_3);
// prepare A_i, Q_i
std::vector<point_t> A_i, Q_i;
A_i.reserve(ring_size), Q_i.reserve(ring_size);
@ -300,18 +285,17 @@ namespace crypto
}
// aggregate secret key (layers 0, 1; G component)
scalar_t w_sec_key_g = agg_coeff_0 * secret_0_xp + agg_coeff_1 * secret_1_f; // + agg_coeff_3 * secret_3_q;
scalar_t w_sec_key_g = agg_coeff_0 * secret_0_xp + agg_coeff_1 * secret_1_f;
DBG_VAL_PRINT(w_sec_key_g * c_point_G);
// aggregate secret key (layer 2; X component)
scalar_t w_sec_key_x = agg_coeff_2 * secret_2_t;
DBG_VAL_PRINT(w_sec_key_x * c_point_X);
// calculate aggregate key image (layers 0, 1, 3; G component)
point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1 /* + agg_coeff_3 * K3 */;
// calculate aggregate key image (layers 0, 1; G component)
point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1;
DBG_VAL_PRINT(key_image);
DBG_VAL_PRINT(K1);
//DBG_VAL_PRINT(K3);
DBG_VAL_PRINT(W_key_image_g);
// calculate aggregate key image (layer 2; X component)
@ -338,15 +322,8 @@ namespace crypto
//DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")");
scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1}
sig.r_g.clear();
sig.r_x.clear();
sig.r_g.reserve(ring_size);
sig.r_x.reserve(ring_size);
for(size_t i = 0; i < ring_size; ++i)
{
sig.r_g.emplace_back(scalar_t::random());
sig.r_x.emplace_back(scalar_t::random());
}
sig.r_g.resize_and_make_random(ring_size);
sig.r_x.resize_and_make_random(ring_size);
for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size)
{
@ -403,6 +380,8 @@ namespace crypto
hsc.add_pub_key(pseudo_out_amount_commitment);
hsc.add_pub_key(pseudo_out_blinded_asset_id);
hsc.add_key_image(ki);
hsc.add_pub_key(sig.K1);
hsc.add_pub_key(sig.K2);
hash input_hash = hsc.calc_hash_no_reduce();
DBG_VAL_PRINT(input_hash);
@ -422,11 +401,6 @@ namespace crypto
scalar_t agg_coeff_2 = hsc.calc_hash();
DBG_VAL_PRINT(agg_coeff_2);
//hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_LAYER_3);
//hsc.add_hash(input_hash);
//scalar_t agg_coeff_3 = hsc.calc_hash();
//DBG_VAL_PRINT(agg_coeff_3);
// prepare A_i, Q_i
std::vector<point_t> A_i, Q_i;
A_i.reserve(ring_size), Q_i.reserve(ring_size);
@ -462,13 +436,11 @@ namespace crypto
DBG_VAL_PRINT(W_pub_keys_x[i]);
}
// calculate aggregate key image (layers 0, 1, 3; G components)
// calculate aggregate key image (layers 0, 1; G components)
point_t W_key_image_g =
agg_coeff_0 * key_image +
agg_coeff_1 * point_t(sig.K1).modify_mul8();
// agg_coeff_3 * point_t(sig.K3).modify_mul8();
DBG_VAL_PRINT(point_t(sig.K1).modify_mul8());
//DBG_VAL_PRINT(point_t(sig.K3).modify_mul8());
DBG_VAL_PRINT(W_key_image_g);
// calculate aggregate key image (layer 2; X component)
@ -498,7 +470,7 @@ namespace crypto
//---------------------------------------------------------------
/*
bool generate_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const point_t& extended_amount_commitment, const key_image& ki,
const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_x, const scalar_t& secret_3_q, uint64_t secret_index, CLSAG_GGXG_signature& sig)
@ -548,6 +520,9 @@ namespace crypto
hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment);
hsc.add_point(c_scalar_1div8 * extended_amount_commitment);
hsc.add_key_image(ki);
hsc.add_pub_key(sig.K1);
hsc.add_pub_key(sig.K2);
hsc.add_pub_key(sig.K3);
hash input_hash = hsc.calc_hash_no_reduce();
DBG_VAL_PRINT(input_hash);
@ -617,7 +592,7 @@ namespace crypto
DBG_VAL_PRINT(w_sec_key_x * c_point_X);
// calculate aggregate key image (layers 0, 1, 3; G component)
point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1 + /*agg_coeff_2 * K2 +*/ agg_coeff_3 * K3;
point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1 + agg_coeff_3 * K3;
DBG_VAL_PRINT(key_image);
DBG_VAL_PRINT(K1);
DBG_VAL_PRINT(K3);
@ -647,15 +622,8 @@ namespace crypto
//DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")");
scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1}
sig.r_g.clear();
sig.r_x.clear();
sig.r_g.reserve(ring_size);
sig.r_x.reserve(ring_size);
for(size_t i = 0; i < ring_size; ++i)
{
sig.r_g.emplace_back(scalar_t::random());
sig.r_x.emplace_back(scalar_t::random());
}
sig.r_g.resize_and_make_random(ring_size);
sig.r_x.resize_and_make_random(ring_size);
for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size)
{
@ -713,6 +681,9 @@ namespace crypto
hsc.add_pub_key(pseudo_out_amount_commitment);
hsc.add_pub_key(extended_amount_commitment);
hsc.add_key_image(ki);
hsc.add_pub_key(sig.K1);
hsc.add_pub_key(sig.K2);
hsc.add_pub_key(sig.K3);
hash input_hash = hsc.calc_hash_no_reduce();
DBG_VAL_PRINT(input_hash);
@ -807,7 +778,7 @@ namespace crypto
return c_prev == sig.c;
}
*/
//---------------------------------------------------------------
@ -868,6 +839,10 @@ namespace crypto
hsc.add_point(c_scalar_1div8 * pseudo_out_blinded_asset_id);
hsc.add_point(c_scalar_1div8 * extended_amount_commitment);
hsc.add_key_image(ki);
hsc.add_pub_key(sig.K1);
hsc.add_pub_key(sig.K2);
hsc.add_pub_key(sig.K3);
hsc.add_pub_key(sig.K4);
hash input_hash = hsc.calc_hash_no_reduce();
DBG_VAL_PRINT(input_hash);
@ -976,15 +951,8 @@ namespace crypto
//DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")");
scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1}
sig.r_g.clear();
sig.r_x.clear();
sig.r_g.reserve(ring_size);
sig.r_x.reserve(ring_size);
for(size_t i = 0; i < ring_size; ++i)
{
sig.r_g.emplace_back(scalar_t::random());
sig.r_x.emplace_back(scalar_t::random());
}
sig.r_g.resize_and_make_random(ring_size);
sig.r_x.resize_and_make_random(ring_size);
for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size)
{
@ -1048,6 +1016,10 @@ namespace crypto
hsc.add_pub_key(pseudo_out_blinded_asset_id);
hsc.add_pub_key(extended_amount_commitment);
hsc.add_key_image(ki);
hsc.add_pub_key(sig.K1);
hsc.add_pub_key(sig.K2);
hsc.add_pub_key(sig.K3);
hsc.add_pub_key(sig.K4);
hash input_hash = hsc.calc_hash_no_reduce();
DBG_VAL_PRINT(input_hash);

View file

@ -1,9 +1,10 @@
// Copyright (c) 2022-2023 Zano Project
// Copyright (c) 2022-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2022-2024 Zano Project
// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// This file contains implementation of CLSAG (s.a. https://eprint.iacr.org/2019/654.pdf by Goodel at el)
// This file contains implementation of the original d-CLSAG (s.a. https://eprint.iacr.org/2019/654.pdf by Goodel at el)
// and the extended d/v-CLSAG version (s.a. https://github.com/hyle-team/docs/blob/master/zano/dv-CLSAG-extension/ by sowle)
//
#pragma once
#include "crypto-sugar.h"
@ -57,11 +58,11 @@ namespace crypto
//
// 3-CLSAG
// 3/2-CLSAG
//
// 3-CLSAG signature (with respect to the group element G, G, X -- that's why 'GGX')
// 3/2-CLSAG signature (with respect to the group element G, G, X -- that's why 'GGX')
struct CLSAG_GGX_signature
{
scalar_t c;
@ -93,12 +94,13 @@ namespace crypto
const public_key& pseudo_out_asset_id, const key_image& ki, const CLSAG_GGX_signature& sig);
/*
//
// 4-CLSAG
// 4/2-CLSAG (eventually, it's not used in Zano)
//
// 4-CLSAG signature (with respect to the group element G, G, X, G -- that's why 'GGXG')
// 4/2-CLSAG signature (with respect to the group element G, G, X, G -- that's why 'GGXG')
struct CLSAG_GGXG_signature
{
scalar_t c;
@ -130,14 +132,14 @@ namespace crypto
bool verify_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment,
const public_key& extended_amount_commitment, const key_image& ki, const CLSAG_GGXG_signature& sig);
*/
//
// 5-CLSAG
// 5/2-CLSAG
//
// 5-CLSAG signature (with respect to the group element G, G, X, X, G -- that's why 'GGXXG')
// 5/2-CLSAG signature (with respect to the group element G, G, X, X, G -- that's why 'GGXXG')
struct CLSAG_GGXXG_signature
{
scalar_t c;

View file

@ -40,7 +40,6 @@ DISABLE_VS_WARNINGS(4146 4244)
void fe_mul(fe, const fe, const fe);
void fe_sq(fe, const fe);
void fe_tobytes(unsigned char *, const fe);
static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
static void ge_p2_0(ge_p2 *);
static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *);
@ -119,7 +118,7 @@ Postconditions:
|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
*/
static void fe_add(fe h, const fe f, const fe g) {
void fe_add(fe h, const fe f, const fe g) {
int32_t f0 = f[0];
int32_t f1 = f[1];
int32_t f2 = f[2];
@ -1425,7 +1424,7 @@ int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
r = p + q
*/
static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
fe_sub(r->Y, p->Y, p->X);
@ -4314,3 +4313,171 @@ void ge_cached_to_p2(ge_p2 *r, const ge_cached *c)
fe_copy(r->Z, c->Z);
}
///////////////////////////
// EXPERIMENTAL
//
// With these select_vartime/ge_scalarmult_base_vartime I got ~25% speed up comparing to the select/ge_scalarmult_base -- sowle
static void select_vartime(ge_precomp *t, int pos, signed char b)
{
unsigned char bnegative = negative(b);
unsigned char babs = b - (((-bnegative) & b) << 1);
const ge_precomp* base;
if (babs == 0)
{
ge_precomp_0(t);
}
else if (bnegative == 0)
{
base = &ge_base[pos][babs - 1];
fe_copy(t->yplusx, base->yplusx);
fe_copy(t->yminusx, base->yminusx);
fe_copy(t->xy2d, base->xy2d);
}
else
{
base = &ge_base[pos][babs - 1];
fe_copy(t->yplusx, base->yminusx);
fe_copy(t->yminusx, base->yplusx);
fe_neg(t->xy2d, base->xy2d);
}
}
void ge_scalarmult_base_vartime(ge_p3 *h, const unsigned char *a)
{
signed char e[64];
signed char carry;
ge_p1p1 r;
ge_p2 s;
ge_precomp t;
int i;
for (i = 0; i < 32; ++i) {
e[2 * i + 0] = (a[i] >> 0) & 15;
e[2 * i + 1] = (a[i] >> 4) & 15;
}
/* each e[i] is between 0 and 15 */
/* e[63] is between 0 and 7 */
carry = 0;
for (i = 0; i < 63; ++i) {
e[i] += carry;
carry = e[i] + 8;
carry >>= 4;
e[i] -= carry << 4;
}
e[63] += carry;
/* each e[i] is between -8 and 8 */
ge_p3_0(h);
for (i = 1; i < 64; i += 2) {
select_vartime(&t, i / 2, e[i]);
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
}
ge_p3_dbl(&r, h); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r);
for (i = 0; i < 64; i += 2) {
select_vartime(&t, i / 2, e[i]);
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
}
}
static void select_custom_precomp_vartime(ge_precomp *t, const precomp_data_t base_precomp, int pos, signed char b)
{
unsigned char bnegative = negative(b);
unsigned char babs = b - (((-bnegative) & b) << 1);
const ge_precomp* base;
if (babs == 0)
{
ge_precomp_0(t);
}
else if (bnegative == 0)
{
base = &base_precomp[pos][babs - 1];
fe_copy(t->yplusx, base->yplusx);
fe_copy(t->yminusx, base->yminusx);
fe_copy(t->xy2d, base->xy2d);
}
else
{
base = &base_precomp[pos][babs - 1];
fe_copy(t->yplusx, base->yminusx);
fe_copy(t->yminusx, base->yplusx);
fe_neg(t->xy2d, base->xy2d);
}
}
void ge_scalarmult_precomp_vartime(ge_p3 *h, const precomp_data_t base_precomp, const unsigned char *a)
{
signed char e[64];
signed char carry;
ge_p1p1 r;
ge_p2 s;
ge_precomp t;
int i;
for (i = 0; i < 32; ++i) {
e[2 * i + 0] = (a[i] >> 0) & 15;
e[2 * i + 1] = (a[i] >> 4) & 15;
}
/* each e[i] is between 0 and 15 */
/* e[63] is between 0 and 7 */
carry = 0;
for (i = 0; i < 63; ++i) {
e[i] += carry;
carry = e[i] + 8;
carry >>= 4;
e[i] -= carry << 4;
}
e[63] += carry;
/* each e[i] is between -8 and 8 */
ge_p3_0(h);
for (i = 1; i < 64; i += 2) {
select_custom_precomp_vartime(&t, base_precomp, i / 2, e[i]);
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
}
ge_p3_dbl(&r, h); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r);
for (i = 0; i < 64; i += 2) {
select_custom_precomp_vartime(&t, base_precomp, i / 2, e[i]);
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
}
}
void ge_p3_to_precomp(ge_precomp *r, const ge_p3* p)
{
fe recip;
fe x;
fe y;
//unsigned char s[32];
fe_invert(recip, p->Z);
fe_mul(x, p->X, recip);
fe_mul(y, p->Y, recip);
fe_sub(r->yminusx, y, x);
fe_add(r->yplusx, y, x);
fe_mul(r->xy2d, x, y);
fe_mul(r->xy2d, r->xy2d, fe_d2);
// to get canonical representation and obtain the very same beautiful numbers for ge_base in crypto-ops-data.c (maybe unnecessary, TODO -- sowle)
//fe_tobytes(s, r->yminusx); fe_frombytes(r->yminusx, s);
//fe_tobytes(s, r->yplusx); fe_frombytes(r->yplusx, s);
//fe_tobytes(s, r->xy2d); fe_frombytes(r->xy2d, s);
}

View file

@ -60,6 +60,7 @@ void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_
extern const fe fe_sqrtm1;
extern const fe fe_d;
extern const fe fe_d2;
int ge_frombytes_vartime(ge_p3 *, const unsigned char *);
/* From ge_p1p1_to_p2.c */
@ -112,12 +113,19 @@ void ge_p2_to_p3(ge_p3 *r, const ge_p2 *t);
void ge_bytes_hash_to_ec(ge_p3 *, const void *, size_t);
void ge_bytes_hash_to_ec_32(ge_p3 *, const unsigned char *);
void ge_cached_to_p2(ge_p2 *r, const ge_cached *c);
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
void ge_p3_0(ge_p3 *h);
void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
void ge_double_scalarmult_base_vartime_p3(ge_p3 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
void ge_scalarmult_vartime_p3(ge_p3 *r, const unsigned char *a, const ge_p3 *A);
void ge_scalarmult_vartime_p3_v2(ge_p3 *r, const unsigned char *a, const ge_p3 *A);
void ge_scalarmult_base_vartime(ge_p3 *h, const unsigned char *a);
/* precomp_data[i][j] = (j + 1) * 256^i * G */
typedef ge_precomp (precomp_data_t)[32][8];
void ge_scalarmult_precomp_vartime(ge_p3 *h, const precomp_data_t base_precomp, const unsigned char *a);
void ge_p3_to_precomp(ge_precomp *r, const ge_p3* p);
extern const fe fe_ma2;
extern const fe fe_ma;
@ -139,6 +147,7 @@ void sc_invert(unsigned char*, const unsigned char*);
void fe_sq(fe h, const fe f);
int fe_isnonzero(const fe f);
void fe_add(fe h, const fe f, const fe g);
void fe_sub(fe h, const fe f, const fe g);
void fe_mul(fe, const fe, const fe);
void fe_frombytes(fe h, const unsigned char *s);

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// Copyright (c) 2020-2023 Zano Project
// Copyright (c) 2020-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2020-2024 Zano Project
// Copyright (c) 2020-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
@ -517,6 +517,24 @@ namespace crypto
m_u64[bit_index >> 6] &= ~(1ull << (bit_index & 63));
}
// the result is guaranteed to be within [ 0; 2 ^ bits_count )
uint64_t get_bits(uint8_t bit_index_first, uint8_t bits_count) const
{
if (bits_count == 0 || bits_count > 64)
return 0;
uint8_t bits_count_m_1 = bits_count - 1;
unsigned int bit_index_last = bit_index_first + bits_count_m_1;
if (bit_index_last > 255)
bit_index_last = 255;
uint64_t result = m_u64[bit_index_first >> 6] >> (bit_index_first & 63);
if (bits_count_m_1 > (bit_index_last & 63))
result |= m_u64[bit_index_last >> 6] << (bits_count_m_1 - (bit_index_last & 63));
uint64_t result_mask = ((1ull << bits_count_m_1) - 1) << 1 | 1; // (just because 1ull << 64 in undefined behaviour, not a 0 as one would expect)
return result & result_mask;
}
// does not reduce
static scalar_t power_of_2(uint8_t exponent)
{
@ -612,9 +630,13 @@ namespace crypto
bool is_zero() const
{
// (0, 1) ~ (0, z, z, 0)
// (0, 1) ~ (0, z, z, 0) for any non-zero z https://www.rfc-editor.org/rfc/rfc8032#page-17
if (fe_isnonzero(m_p3.X) != 0)
return false;
return false; // x != 0
if (fe_isnonzero(m_p3.Z) == 0)
return false; // z == 0
if (fe_isnonzero(m_p3.T) != 0)
return false; // t != 0
fe y_minus_z;
fe_sub(y_minus_z, m_p3.Y, m_p3.Z);
return fe_isnonzero(y_minus_z) == 0;
@ -707,14 +729,15 @@ namespace crypto
friend point_t operator*(const scalar_t& lhs, const point_t& rhs)
{
point_t result;
ge_scalarmult_p3(&result.m_p3, lhs.m_s, &rhs.m_p3);
//ge_scalarmult_p3(&result.m_p3, lhs.m_s, &rhs.m_p3);
ge_scalarmult_vartime_p3(&result.m_p3, lhs.m_s, &rhs.m_p3);
return result;
}
point_t& operator*=(const scalar_t& rhs)
{
// TODO: ge_scalarmult_vartime_p3
ge_scalarmult_p3(&m_p3, rhs.m_s, &m_p3);
//ge_scalarmult_p3(&m_p3, rhs.m_s, &m_p3);
ge_scalarmult_vartime_p3(&m_p3, rhs.m_s, &m_p3);
return *this;
}
@ -723,7 +746,8 @@ namespace crypto
point_t result;
scalar_t reciprocal;
sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]);
ge_scalarmult_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3);
//ge_scalarmult_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3);
ge_scalarmult_vartime_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3);
return result;
}
@ -742,6 +766,24 @@ namespace crypto
return *this;
}
point_t modify_mul_pow_2(size_t power)
{
if (power > 0)
{
ge_p1p1 p1;
ge_p2 p2;
ge_p3_to_p2(&p2, &m_p3);
for (size_t i = 1; i < power; ++i)
{
ge_p2_dbl(&p1, &p2);
ge_p1p1_to_p2(&p2, &p1);
}
ge_p2_dbl(&p1, &p2);
ge_p1p1_to_p3(&m_p3, &p1);
}
return *this;
}
// returns a * this + G
point_t mul_plus_G(const scalar_t& a) const
{
@ -867,7 +909,8 @@ namespace crypto
friend point_t operator*(const scalar_t& lhs, const point_g_t&)
{
point_t result;
ge_scalarmult_base(&result.m_p3, &lhs.m_s[0]);
//ge_scalarmult_base(&result.m_p3, &lhs.m_s[0]);
ge_scalarmult_base_vartime(&result.m_p3, &lhs.m_s[0]);
return result;
}
@ -876,7 +919,8 @@ namespace crypto
point_t result;
scalar_t reciprocal;
sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]);
ge_scalarmult_base(&result.m_p3, &reciprocal.m_s[0]);
//ge_scalarmult_base(&result.m_p3, &reciprocal.m_s[0]);
ge_scalarmult_base_vartime(&result.m_p3, &reciprocal.m_s[0]);
return result;
}
@ -885,6 +929,42 @@ namespace crypto
}; // struct point_g_t
void construct_precomp_data(precomp_data_t precomp_data, const point_t& point);
//
// point_pc_t -- point with 30kB of precomputed data, which make possible to do very fast single scalar multiplication
//
struct point_pc_t : public point_t
{
constexpr point_pc_t(const int32_t(&v)[40], const precomp_data_t* precomp_data_p)
: point_t(v)
, m_precomp_data_p(precomp_data_p)
{
//construct_precomp_data(m_precomp_data, *this);
}
friend point_t operator*(const scalar_t& lhs, const point_pc_t& self)
{
point_t result;
ge_scalarmult_precomp_vartime(&result.m_p3, *self.m_precomp_data_p, &lhs.m_s[0]);
return result;
}
friend point_t operator/(const point_pc_t& self, const scalar_t& rhs)
{
point_t result;
scalar_t reciprocal;
sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]);
ge_scalarmult_precomp_vartime(&result.m_p3, *self.m_precomp_data_p, &reciprocal.m_s[0]);
return result;
}
static_assert(sizeof(crypto::public_key) == 32, "size error");
const precomp_data_t* m_precomp_data_p;
}; // struct point_pc_t
//
// vector of scalars
//
@ -1042,18 +1122,30 @@ namespace crypto
//
// Global constants (checked in crypto_constants test)
// Global constants (checked in crypto_constants and crypto_generators_precomp tests)
//
static constexpr point_t c_point_0 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
static constexpr point_g_t c_point_G {{ 25485296, 5318399, 8791791, -8299916, -14349720, 6939349, -3324311, -7717049, 7287234, -6577708, -758052, -1832720, 13046421, -4857925, 6576754, 14371947, -13139572, 6845540, -2198883, -4003719, -947565, 6097708, -469190, 10704810, -8556274, -15589498, -16424464, -16608899, 14028613, -5004649, 6966464, -2456167, 7033433, 6781840, 28785542, 12262365, -2659449, 13959020, -21013759, -5262166 }};
static constexpr point_t c_point_H {{ 20574939, 16670001, -29137604, 14614582, 24883426, 3503293, 2667523, 420631, 2267646, -4769165, -11764015, -12206428, -14187565, -2328122, -16242653, -788308, -12595746, -8251557, -10110987, 853396, -4982135, 6035602, -21214320, 16156349, 977218, 2807645, 31002271, 5694305, -16054128, 5644146, -15047429, -568775, -22568195, -8089957, -27721961, -10101877, -29459620, -13359100, -31515170, -6994674 }};
static constexpr point_t c_point_H2 {{ 1318371, 14804112, 12545972, -13482561, -12089798, -16020744, -21221907, -8410994, -33080606, 11275578, 3807637, 11185450, -23227561, -12892068, 1356866, -1025012, -8022738, -8139671, -20315029, -13916324, -6475650, -7025596, 12403179, -5139984, -12068178, 10445584, -14826705, -4927780, 13964546, 12525942, -2314107, -10566315, 32243863, 15603849, 5154154, 4276633, -20918372, -15718796, -26386151, 8434696 }};
static constexpr point_t c_point_U {{ 30807552, 984924, 23426137, -5598760, 7545909, 16325843, 993742, 2594106, -31962071, -959867, 16454190, -4091093, 1197656, 13586872, -9269020, -14133290, 1869274, 13360979, -24627258, -10663086, 2212027, 1198856, 20515811, 15870563, -23833732, 9839517, -19416306, 11567295, -4212053, 348531, -2671541, 484270, -19128078, 1236698, -16002690, 9321345, 9776066, 10711838, 11187722, -16371275 }};
static constexpr point_t c_point_X {{ 25635916, -5459446, 5768861, 5666160, -6357364, -12939311, 29490001, -4543704, -31266450, -2582476, 23705213, 9562626, -716512, 16560168, 7947407, 2039790, -2752711, 4742449, 3356761, 16338966, 17303421, -5790717, -5684800, 12062431, -3307947, 8139265, -26544839, 12058874, 3452748, 3359034, 26514848, -6060876, 31255039, 11154418, -21741975, -3782423, -19871841, 5729859, 21754676, -12454027 }};
static constexpr point_t c_point_H_plus_G {{ 12291435, 3330843, -3390294, 13894858, -1099584, -6848191, 12040668, -15950068, -7494633, 12566672, -5526901, -16645799, -31081168, -1095427, -13082463, 4573480, -11255691, 4344628, 33477173, 11137213, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -6229107, -9324867, 558657, 6493750, 4895261, 12642545, 9549220, 696086, 21894285, -10521807 }};
static constexpr point_t c_point_H_minus_G {{ -28347682, 3523701, -3380175, -14453727, 4238027, -6032522, 20235758, 4091609, 12557126, -8064113, 4212476, -13419094, -114185, -7650727, -24238, 16663404, 23676363, -6819610, 18286466, 8714527, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -20450317, 13815641, -11604061, -447489, 27380225, 9400847, -8551293, -1173627, -28110171, 14241295 }};
namespace xdetails
{
extern const precomp_data_t c_point_H_precomp_data;
extern const precomp_data_t c_point_H2_precomp_data;
extern const precomp_data_t c_point_U_precomp_data;
extern const precomp_data_t c_point_X_precomp_data;
extern const precomp_data_t c_point_H_plus_G_precomp_data;
extern const precomp_data_t c_point_H_minus_G_precomp_data;
};
inline constexpr point_t c_point_0 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
inline constexpr point_g_t c_point_G {{ 25485296, 5318399, 8791791, -8299916, -14349720, 6939349, -3324311, -7717049, 7287234, -6577708, -758052, -1832720, 13046421, -4857925, 6576754, 14371947, -13139572, 6845540, -2198883, -4003719, -947565, 6097708, -469190, 10704810, -8556274, -15589498, -16424464, -16608899, 14028613, -5004649, 6966464, -2456167, 7033433, 6781840, 28785542, 12262365, -2659449, 13959020, -21013759, -5262166 }};
inline constexpr point_pc_t c_point_H {{ 20574939, 16670001, -29137604, 14614582, 24883426, 3503293, 2667523, 420631, 2267646, -4769165, -11764015, -12206428, -14187565, -2328122, -16242653, -788308, -12595746, -8251557, -10110987, 853396, -4982135, 6035602, -21214320, 16156349, 977218, 2807645, 31002271, 5694305, -16054128, 5644146, -15047429, -568775, -22568195, -8089957, -27721961, -10101877, -29459620, -13359100, -31515170, -6994674 }, &xdetails::c_point_H_precomp_data };
inline constexpr point_pc_t c_point_H2 {{ 1318371, 14804112, 12545972, -13482561, -12089798, -16020744, -21221907, -8410994, -33080606, 11275578, 3807637, 11185450, -23227561, -12892068, 1356866, -1025012, -8022738, -8139671, -20315029, -13916324, -6475650, -7025596, 12403179, -5139984, -12068178, 10445584, -14826705, -4927780, 13964546, 12525942, -2314107, -10566315, 32243863, 15603849, 5154154, 4276633, -20918372, -15718796, -26386151, 8434696 }, &xdetails::c_point_H2_precomp_data };
inline constexpr point_pc_t c_point_U {{ 30807552, 984924, 23426137, -5598760, 7545909, 16325843, 993742, 2594106, -31962071, -959867, 16454190, -4091093, 1197656, 13586872, -9269020, -14133290, 1869274, 13360979, -24627258, -10663086, 2212027, 1198856, 20515811, 15870563, -23833732, 9839517, -19416306, 11567295, -4212053, 348531, -2671541, 484270, -19128078, 1236698, -16002690, 9321345, 9776066, 10711838, 11187722, -16371275 }, &xdetails::c_point_U_precomp_data };
inline constexpr point_pc_t c_point_X {{ 25635916, -5459446, 5768861, 5666160, -6357364, -12939311, 29490001, -4543704, -31266450, -2582476, 23705213, 9562626, -716512, 16560168, 7947407, 2039790, -2752711, 4742449, 3356761, 16338966, 17303421, -5790717, -5684800, 12062431, -3307947, 8139265, -26544839, 12058874, 3452748, 3359034, 26514848, -6060876, 31255039, 11154418, -21741975, -3782423, -19871841, 5729859, 21754676, -12454027 }, &xdetails::c_point_X_precomp_data };
inline constexpr point_pc_t c_point_H_plus_G {{ 12291435, 3330843, -3390294, 13894858, -1099584, -6848191, 12040668, -15950068, -7494633, 12566672, -5526901, -16645799, -31081168, -1095427, -13082463, 4573480, -11255691, 4344628, 33477173, 11137213, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -6229107, -9324867, 558657, 6493750, 4895261, 12642545, 9549220, 696086, 21894285, -10521807 }, &xdetails::c_point_H_plus_G_precomp_data };
inline constexpr point_pc_t c_point_H_minus_G {{ -28347682, 3523701, -3380175, -14453727, 4238027, -6032522, 20235758, 4091609, 12557126, -8064113, 4212476, -13419094, -114185, -7650727, -24238, 16663404, 23676363, -6819610, 18286466, 8714527, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -20450317, 13815641, -11604061, -447489, 27380225, 9400847, -8551293, -1173627, -28110171, 14241295 }, &xdetails::c_point_H_minus_G_precomp_data };
//
// hash functions' helper
//
@ -1250,6 +1342,15 @@ namespace crypto
return hs_calculator.calc_hash();
}
static scalar_t hs(const char(&str32)[32], const scalar_t& s, const crypto::public_key& pk)
{
hs_t hs_calculator(2);
hs_calculator.add_32_chars(str32);
hs_calculator.add_scalar(s);
hs_calculator.add_pub_key(pk);
return hs_calculator.calc_hash();
}
static scalar_t hs(const crypto::public_key& pk, const uint64_t i)
{
hs_t hs_calculator(2);

25
src/crypto/msm.cpp Normal file
View file

@ -0,0 +1,25 @@
// Copyright (c) 2023-2023 Zano Project
// Copyright (c) 2023-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include "epee/include/misc_log_ex.h"
//#include "zarcanum.h"
#include "msm.h"
//#include "../currency_core/crypto_config.h" // TODO: move it to the crypto
//#include "../common/crypto_stream_operators.h" // TODO: move it to the crypto
#if 0
# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl
# define DBG_PRINT(x) std::cout << x << std::endl
#else
# define DBG_VAL_PRINT(x) (void(0))
# define DBG_PRINT(x) (void(0))
#endif
namespace crypto
{
} // namespace crypto

173
src/crypto/msm.h Normal file
View file

@ -0,0 +1,173 @@
// Copyright (c) 2023-2023 Zano Project (https://zano.org/)
// Copyright (c) 2023-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
// This file contains Multi-Scalar Multiplication routines
#include "epee/include/misc_log_ex.h"
#include "crypto-sugar.h"
namespace crypto
{
template<typename CT>
bool msm_and_check_zero_naive(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
{
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
point_t result = summand;
for (size_t i = 0; i < g_scalars.size(); ++i)
result += g_scalars[i] * CT::get_generator(false, i);
for (size_t i = 0; i < h_scalars.size(); ++i)
result += h_scalars[i] * CT::get_generator(true, i);
if (!result.is_zero())
{
LOG_PRINT_L0("msm result is non zero: " << result);
return false;
}
return true;
}
// https://eprint.iacr.org/2022/999.pdf
// "Pippenger algorithm [1], and its variant that is widely used in the ZK space is called the bucket method"
template<typename CT>
bool msm_and_check_zero_pippenger_v3(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, uint8_t c)
{
// TODO: with c = 8 and with direct access got much worse result than with c = 7 and get_bits() for N = 128..256, consider checking again for bigger datasets (N>256)
// TODO: consider preparing a cached generators' points
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
CHECK_AND_ASSERT_MES(c < 10, false, "c is too big");
size_t C = 1ull << c;
// k_max * c + (c-1) >= max_bit_idx
//
// max_bit_idx - (c - 1) max_bit_idx - (c - 1) + (c - 1) max_bit_idx
// k_max = ceil ( --------------------- ) = floor ( ------------------------------ ) = floor ( ----------- )
// c c c
const size_t b = 253; // the maximum number of bits in x https://eprint.iacr.org/2022/999.pdf TODO: we may also scan for maximum bit used in all the scalars if all the scalars are small
const size_t max_bit_idx = b - 1;
const size_t k_max = max_bit_idx / c;
const size_t K = k_max + 1;
std::vector<point_t> buckets(C * K);
std::vector<bool> buckets_inited(C * K);
std::vector<point_t> Sk(K);
std::vector<bool> Sk_inited(K);
std::vector<point_t> Gk(K);
std::vector<bool> Gk_inited(K);
// first loop, calculate partial bucket sums
for (size_t n = 0; n < g_scalars.size(); ++n)
{
for (size_t k = 0; k < K; ++k)
{
uint64_t l = g_scalars[n].get_bits((uint8_t)(k * c), c); // l in [0; 2^c-1]
if (l != 0)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
buckets[bucket_id] += CT::get_generator(false, n);
else
{
buckets[bucket_id] = CT::get_generator(false, n);
buckets_inited[bucket_id] = true;
}
}
}
}
// still the first loop (continued)
for (size_t n = 0; n < h_scalars.size(); ++n)
{
for (size_t k = 0; k < K; ++k)
{
uint64_t l = h_scalars[n].get_bits((uint8_t)(k * c), c); // l in [0; 2^c-1]
if (l != 0)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
buckets[bucket_id] += CT::get_generator(true, n);
else
{
buckets[bucket_id] = CT::get_generator(true, n);
buckets_inited[bucket_id] = true;
}
}
}
}
// the second loop
for (size_t l = C - 1; l > 0; --l)
{
for (size_t k = 0; k < K; ++k)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
{
if (Sk_inited[k])
Sk[k] += buckets[bucket_id];
else
{
Sk[k] = buckets[bucket_id];
Sk_inited[k] = true;
}
}
if (Sk_inited[k])
{
if (Gk_inited[k])
Gk[k] += Sk[k];
else
{
Gk[k] = Sk[k];
Gk_inited[k] = true;
}
}
}
}
// the third loop: Horners rule
point_t result = Gk_inited[K - 1] ? Gk[K - 1] : c_point_0;
for (size_t k = K - 2; k != SIZE_MAX; --k)
{
result.modify_mul_pow_2(c);
if (Gk_inited[k])
result += Gk[k];
}
result += summand;
if (!result.is_zero())
{
LOG_PRINT_L0("multiexp result is non zero: " << result);
return false;
}
return true;
}
// Just switcher
template<typename CT>
bool msm_and_check_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
{
//return msm_and_check_zero_naive<CT>(g_scalars, h_scalars, summand);
return msm_and_check_zero_pippenger_v3<CT>(g_scalars, h_scalars, summand, 7);
}
} // namespace crypto

View file

@ -234,7 +234,7 @@ namespace crypto
const size_t m = std::max(static_cast<uint64_t>(1), constexpr_ceil_log_n(ring_size, n));
const size_t N = constexpr_pow(m, n);
const size_t mn = m * n;
//const size_t mn = m * n;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.Pk.size() == m, 1);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.f.size() == m * (n - 1), 2);

View file

@ -20,7 +20,14 @@ namespace crypto
// Disclaimer: shouldn't be used in production code until the security proofs and the code are peer-reviewed.
//
// m+2 group elements, m(n-1)+2 field elements
// m+2 group elements, m(n-1)+2 field elements.
// Assuming fixed n=4, m = log4(ring_sz) the size is (log4(ring_sz) + 2) group elements and (3*log4(ring_sz) + 2) or, in total, (4*log4(ring_sz) + 4) 32-bytes words
// ring_sz = m (inputs number)
// sig_count = k (outputs number)
// thus:
// k * (log4(m) + 2) group elements and k * (3*log4(m) + 2) field elements
struct BGE_proof
{
public_key A; // premultiplied by 1/8

View file

@ -716,7 +716,7 @@ namespace crypto
point_t GH_exponents = c_point_0;
CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents);
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
bool result = msm_and_check_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
if (result)
DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL);
return result;

View file

@ -734,7 +734,7 @@ namespace crypto
point_t GH_exponents = c_point_0;
CT::calc_pedersen_commitment_2(G_scalar, H_scalar, H2_scalar, GH_exponents);
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
bool result = msm_and_check_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
if (result)
DBG_PRINT(ENDL << " . . . . bppe_verify() -- SUCCEEDED!!!" << ENDL);
return result;

View file

@ -41,7 +41,7 @@ namespace crypto
////////////////////////////////////////
struct bpp_ct_generators_HGX
{
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators below
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators in range_proofs.cpp
static const point_t& bpp_G;
static const point_t& bpp_H;
static const point_t& bpp_H2;
@ -49,7 +49,7 @@ namespace crypto
struct bpp_ct_generators_UGX
{
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators below
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators in range_proofs.cpp
static const point_t& bpp_G;
static const point_t& bpp_H;
static const point_t& bpp_H2;
@ -138,32 +138,11 @@ namespace crypto
typedef bpp_crypto_trait_zano<bpp_ct_generators_HGX, 128, 16> bpp_crypto_trait_Zarcanum;
// efficient multiexponentiation (naive stub implementation atm, TODO)
template<typename CT>
bool multiexp_and_check_being_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
{
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
point_t result = summand;
for (size_t i = 0; i < g_scalars.size(); ++i)
result += g_scalars[i] * CT::get_generator(false, i);
for (size_t i = 0; i < h_scalars.size(); ++i)
result += h_scalars[i] * CT::get_generator(true, i);
if (!result.is_zero())
{
LOG_PRINT_L0("multiexp result is non zero: " << result);
return false;
}
return true;
}
} // namespace crypto
#include "epee/include/profile_tools.h" // <- remove this, sowle
#include "msm.h"
#include "range_proof_bpp.h"
#include "range_proof_bppe.h"

View file

@ -205,7 +205,7 @@ namespace crypto
TRY_ENTRY()
{
DBG_PRINT("zarcanum_verify_proof");
bool r = false;
//bool r = false;
//std::cout << "===== zarcanum_verify_proof =====" << ENDL
// << "m: " << m << ENDL

View file

@ -126,6 +126,9 @@ namespace crypto
template<generator_tag gen>
inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept;
// TODO @#@# make optimized version inline bool verify_schnorr_sig(const hash& m, const point_t& A, const generic_schnorr_sig& sig) noexcept;
// and change check_tx_balance() accordingly
template<>
inline bool verify_schnorr_sig<gt_G>(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept
{

View file

@ -1345,7 +1345,12 @@ bool blockchain_storage::validate_miner_transaction(const block& b,
return false;
}
uint64_t block_reward = base_reward + fee;
uint64_t block_reward = base_reward;
// before HF4: add tx fee to the block reward; after HF4: burn it
if (b.miner_tx.version < TRANSACTION_VERSION_POST_HF4)
{
block_reward += fee;
}
crypto::hash tx_id_for_post_hf4_era = b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4 ? get_transaction_hash(b.miner_tx) : null_hash;
if (!check_tx_balance(b.miner_tx, tx_id_for_post_hf4_era, block_reward))
@ -1360,13 +1365,10 @@ bool blockchain_storage::validate_miner_transaction(const block& b,
return false;
}
if (b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4)
if (!verify_asset_surjection_proof(b.miner_tx, tx_id_for_post_hf4_era))
{
if (!verify_asset_surjection_proof(b.miner_tx, tx_id_for_post_hf4_era))
{
LOG_ERROR("asset surjection proof verification failed for miner tx");
return false;
}
LOG_ERROR("asset surjection proof verification failed for miner tx");
return false;
}
LOG_PRINT_MAGENTA("Mining tx verification ok, blocks_size_median = " << blocks_size_median, LOG_LEVEL_2);
@ -1522,6 +1524,7 @@ bool blockchain_storage::create_block_template(const create_block_template_param
stakeholder_address,
b.miner_tx,
resp.block_reward_without_fee,
resp.block_reward,
get_tx_version(height, m_core_runtime_config.hard_forks),
ex_nonce,
CURRENCY_MINER_TX_MAX_OUTS,
@ -2046,9 +2049,18 @@ bool blockchain_storage::is_reorganize_required(const block_extended_info& main_
wide_difficulty_type main_pow_diff_begin = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), connection_point.height - 1, false);
main_cumul_diff.pow_diff = main_pow_diff_end - main_pow_diff_begin;
//TODO: measurement of precise cumulative difficult
boost::multiprecision::uint1024_t alt = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff);
boost::multiprecision::uint1024_t main = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff);
boost::multiprecision::uint1024_t alt = 0;
boost::multiprecision::uint1024_t main = 0;
if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, alt_chain_bei.height))
{
alt = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff);
main = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff);
}
else
{
alt = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff);
main = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff);
}
LOG_PRINT_L1("[FORK_CHOICE]: " << ENDL
<< "difficulty_pow_at_split_point:" << difficulty_pow_at_split_point << ENDL
<< "difficulty_pos_at_split_point:" << difficulty_pos_at_split_point << ENDL
@ -2065,6 +2077,21 @@ bool blockchain_storage::is_reorganize_required(const block_extended_info& main_
return false;
else
{
if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
{
// prefer blocks with more summary fee(to motivate stakers include transactions)
// since we don't have "summary block fee" field yet, we can use this_block_tx_fee_median multiplied to transactions
// count as an indirect measure of sumarry paid fee. If this approach won't be doing it's job it's subject
// to reconsider and introducing additional field in block_extended_info structure
if (alt_chain_bei.this_block_tx_fee_median * alt_chain_bei.bl.tx_hashes.size() >
main_chain_bei.this_block_tx_fee_median * main_chain_bei.bl.tx_hashes.size())
{
//with the rest equal, alt block has more fees in it, prefer it
return true;
}
}
if (!is_pos_block(main_chain_bei.bl))
return false; // do not reorganize on the same cummul diff if it's a PoW block
@ -2660,6 +2687,215 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map<uint64_t, uint64_t>& amounts_to_up_index_limit_cache) const
{
size_t decoys_count = details.offsets.size();
uint64_t amount = details.amount;
uint64_t outs_container_size = m_db_outputs.get_item_size(details.amount);
if (!outs_container_size)
{
LOG_ERROR("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: not outs for amount " << amount << ", wallet should use some real outs when it lookup for some mix, so, at least one out for this amount should exist");
return false;//actually this is strange situation, wallet should use some real outs when it lookup for some mix, so, at least one out for this amount should exist
}
//it is not good idea to use top fresh outs, because it increases possibility of transaction canceling on split
//lets find upper bound of not fresh outs
size_t up_index_limit = 0;
auto it_limit = amounts_to_up_index_limit_cache.find(amount);
if (it_limit == amounts_to_up_index_limit_cache.end())
{
up_index_limit = find_end_of_allowed_index(amount);
amounts_to_up_index_limit_cache[up_index_limit];
}
else
{
up_index_limit = it_limit->second;
}
CHECK_AND_ASSERT_MES(up_index_limit <= outs_container_size, false, "internal error: find_end_of_allowed_index returned wrong index=" << up_index_limit << ", with amount_outs.size = " << outs_container_size);
if (up_index_limit >= decoys_count)
{
std::set<size_t> used;
used.insert(details.own_global_index);
for (uint64_t j = 0; j != decoys_count || used.size() >= up_index_limit;)
{
size_t g_index_initial = crypto::rand<size_t>() % up_index_limit;
size_t g_index = g_index_initial;
//enumerate via whole loop from g_index to up_index_limit and then from 0 to g_index
while (true)
{
if (!used.count(g_index))
break;
g_index++;
if (g_index >= up_index_limit)
g_index = 0;
if (g_index == g_index_initial)
{
// we enumerated full circle and couldn't find needed amount of outs
LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << decoys_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total", LOG_LEVEL_0);
return true;
}
}
bool added = add_out_to_get_random_outs(result_outs, amount, g_index, decoys_count, req.use_forced_mix_outs, req.height_upper_limit);
used.insert(g_index);
if (added)
++j;
}
if (result_outs.outs.size() < decoys_count)
{
LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << decoys_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total", LOG_LEVEL_0);
}
return true;
}
else
{
size_t added = 0;
for (size_t i = 0; i != up_index_limit; i++)
added += add_out_to_get_random_outs(result_outs, amount, i, decoys_count, req.use_forced_mix_outs, req.height_upper_limit) ? 1 : 0;
LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << decoys_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs", LOG_LEVEL_0);
return true;
}
}
//------------------------------------------------------------------
bool blockchain_storage::get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map<uint64_t, uint64_t>& amounts_to_up_index_limit_cache) const
{
std::set<uint64_t> used;
used.insert(details.own_global_index);
for (auto offset : details.offsets)
{
//perfectly we would need to find transaction's output on the given height, with the given probability
//of being coinbase(coinbase outputs should be included less in decoy selection algorithm)
bool is_coinbase = (crypto::rand<uint64_t>() % 101) > req.coinbase_percents ? false : true;
//TODO: Consider including PoW coinbase to transactions(does it needed?)
// convert offset to estimated height
uint64_t estimated_h = this->get_current_blockchain_size() - 1 - offset;
//make sure it's after zc hardfork
if (estimated_h < m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM])
{
LOG_ERROR("Wrong estimated offset(" << offset << "), it hits zone before zarcanum hardfork");
return false;
}
#define TARGET_RANDOM_OUTS_SELECTIOM_POOL_MIN 10
//try to find output around given H
std::vector<uint64_t> selected_global_indexes;
auto process_tx = [&](const crypto::hash& tx_id) {
auto tx_ptr = m_db_transactions.find(tx_id);
CHECK_AND_ASSERT_THROW_MES(tx_ptr, "internal error: tx_id " << tx_id << " around estimated_h = " << estimated_h << " not found in db");
//go through tx outputs
for (size_t i = 0; i != tx_ptr->tx.vout.size(); i++)
{
if (tx_ptr->tx.vout[i].type() != typeid(tx_out_zarcanum))
{
continue;
}
const tx_out_zarcanum& z_out = boost::get<tx_out_zarcanum>(tx_ptr->tx.vout[i]);
// NOTE: second part of condition (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND && ..) might be not accurate
// since the wallet might want to request more inputs then it planning to do mixins. For now let's keep it this way and fix
// it if we see the problems about it.
if (z_out.mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX || (z_out.mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND && z_out.mix_attr < details.offsets.size()))
{
continue;
}
// skip spent outptus
if (tx_ptr->m_spent_flags[i])
{
continue;
}
if (used.find(tx_ptr->m_global_output_indexes[i]) != used.end())
{
continue;
}
// add output
// note: code that will process selected_global_indes will be revisiting transactions entries to obtain all
// needed data, that should work relatively effective because of on-top-of-db cache keep daya unserialized
selected_global_indexes.push_back(tx_ptr->m_global_output_indexes[i]);
}
};
while (selected_global_indexes.size() < TARGET_RANDOM_OUTS_SELECTIOM_POOL_MIN)
{
auto block_ptr = m_db_blocks.get(estimated_h);
if (is_coinbase && is_pos_block(block_ptr->bl) )
{
process_tx(get_transaction_hash(block_ptr->bl.miner_tx));
}
else
{
//looking for regular output of regular transactions
for (auto tx_id : block_ptr->bl.tx_hashes)
{
process_tx(tx_id);
}
}
if(estimated_h)
estimated_h--;
else
{
//likely unusual situation when blocks enumerated all way back to genesis
//let's check if we have at least something
if (!selected_global_indexes.size())
{
//need to regenerate offsets
return false;
}
}
}
//pick up a random output from selected_global_indes
uint64_t global_index = selected_global_indexes[crypto::rand<uint64_t>() % selected_global_indexes.size()];
bool res = add_out_to_get_random_outs(result_outs, details.amount, global_index, details.offsets.size(), req.use_forced_mix_outs, req.height_upper_limit);
CHECK_AND_ASSERT_THROW_MES(res, "Failed to add_out_to_get_random_outs([" << global_index << "]) at postzarcanum era");
used.insert(global_index);
}
return true;
}
//------------------------------------------------------------------
bool blockchain_storage::get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const
{
CRITICAL_REGION_LOCAL(m_read_lock);
LOG_PRINT_L3("[get_random_outs_for_amounts] amounts: " << req.amounts.size());
std::map<uint64_t, uint64_t> amounts_to_up_index_limit_cache;
uint64_t count_zarcanum_blocks = 0;
if(is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
count_zarcanum_blocks = this->get_current_blockchain_size() - m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM];
for (size_t i = 0; i != req.amounts.size(); i++)
{
uint64_t amount = req.amounts[i].amount;
//const std::vector<uint64_t>& offsets = req.amounts[i].offsets;
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount());
result_outs.amount = amount;
bool r = false;
if (amount == 0 && count_zarcanum_blocks > 20000)
{
//zarcanum era inputs
r = get_target_outs_for_postzarcanum(req, req.amounts[i], result_outs, amounts_to_up_index_limit_cache);
}
else
{
//zarcanum era inputs
r = get_target_outs_for_amount_prezarcanum(req, req.amounts[i], result_outs, amounts_to_up_index_limit_cache);
}
if (!r)
return false;
}
return true;
}
//------------------------------------------------------------------
boost::multiprecision::uint128_t blockchain_storage::total_coins() const
{
CRITICAL_REGION_LOCAL(m_read_lock);
@ -4096,6 +4332,7 @@ uint64_t blockchain_storage::get_tx_fee_median() const
//------------------------------------------------------------------
uint64_t blockchain_storage::get_alias_coast(const std::string& alias) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
uint64_t median_fee = get_tx_fee_median();
//CHECK_AND_ASSERT_MES_NO_RET(median_fee, "can't calculate median");
@ -4106,9 +4343,29 @@ uint64_t blockchain_storage::get_alias_coast(const std::string& alias) const
return get_alias_coast_from_fee(alias, median_fee);
}
//------------------------------------------------------------------
uint64_t blockchain_storage::get_tx_fee_window_value_median() const
{
// calc it every time and cache it so it won't recalculated before next block
// it's effective because it's not affect sync time and needed only when node is synced
// and processing transactions
misc_utils::median_helper<uint64_t, uint64_t> mh;
for (uint64_t i = 0; i < CORE_FEE_BLOCKS_LOOKUP_WINDOW; i++)
{
uint64_t h = m_db_blocks.size() - 1 - i;
if (h >= m_db_blocks.size())
break;
auto block_ptr = m_db_blocks[h];
CHECK_AND_ASSERT_THROW_MES(block_ptr, "Unexpected missing block " << h << " in get_tx_fee_window_value_median");
mh.push_item(block_ptr->block_cumulative_size, 0);
}
return (mh.get_median() + mh.get_avg())/2;
}
//------------------------------------------------------------------
bool blockchain_storage::unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp)
{
size_t cnt_serv_attach = get_service_attachments_count_in_tx(tx);
if (cnt_serv_attach == 0)
return true;
@ -4420,7 +4677,7 @@ uint64_t blockchain_storage::tx_fee_median_for_height(uint64_t h)const
//------------------------------------------------------------------
bool blockchain_storage::validate_all_aliases_for_new_median_mode()
{
LOG_PRINT_L0("Started reinitialization of median fee...");
LOG_PRINT_L0("Started reinitialization of median fee...");
math_helper::once_a_time_seconds<10> log_idle;
uint64_t sz = m_db_blocks.size();
for (uint64_t i = 0; i != sz; i++)
@ -4536,7 +4793,7 @@ bool blockchain_storage::print_tx_outputs_lookup(const crypto::hash& tx_id)const
return true;
}
//------------------------------------------------------------------
bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_have_explicit_asset_ids)
bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_have_explicit_native_asset_ids)
{
if (tx.version <= TRANSACTION_VERSION_PRE_HF4)
return true;
@ -4544,13 +4801,13 @@ bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_hav
// ( assuming that post-HF4 txs can only have tx_out_zarcanum outs )
bool r = false;
// if all tx inputs have explicit asset id AND it does not emit a new asset THEN all outputs must have explicit asset id (native coin)
if (all_tx_ins_have_explicit_asset_ids && !is_asset_emitting_transaction(tx))
// if all tx inputs have explicit native asset id AND it does not emit a new asset THEN all outputs must have explicit asset id (native coin)
if (all_tx_ins_have_explicit_native_asset_ids && !is_asset_emitting_transaction(tx))
{
for(size_t j = 0, k = tx.vout.size(); j < k; ++j)
{
r = crypto::point_t(boost::get<tx_out_zarcanum>(tx.vout[j]).blinded_asset_id).modify_mul8().to_public_key() == native_coin_asset_id;
CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has a non-explicit asset id");
CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has a non-explicit asset id in a tx where all inputs have an explicit native asset id");
}
}
else // otherwise all outputs must have hidden asset id (unless they burn money by sending them to null pubkey)
@ -4559,7 +4816,7 @@ bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_hav
{
const tx_out_zarcanum& zo = boost::get<tx_out_zarcanum>(tx.vout[j]);
r = zo.stealth_address == null_pkey || crypto::point_t(zo.blinded_asset_id).modify_mul8().to_public_key() != native_coin_asset_id;
CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has an explicit asset id");
CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has an explicit asset id in a tx where not all inputs have an explicit native asset id");
}
}
return true;
@ -4605,7 +4862,7 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
{
size_t sig_index = 0;
max_used_block_height = 0;
bool all_tx_ins_have_explicit_asset_ids = true;
bool all_tx_ins_have_explicit_native_asset_ids = true;
auto local_check_key_image = [&](const crypto::key_image& ki) -> bool
{
@ -4667,7 +4924,7 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
if (!local_check_key_image(in_zc.k_image))
return false;
if (!check_tx_input(tx, sig_index, in_zc, tx_prefix_hash, max_used_block_height, all_tx_ins_have_explicit_asset_ids))
if (!check_tx_input(tx, sig_index, in_zc, tx_prefix_hash, max_used_block_height, all_tx_ins_have_explicit_native_asset_ids))
{
LOG_ERROR("Failed to validate zc input #" << sig_index << " in tx: " << tx_prefix_hash);
return false;
@ -4690,7 +4947,7 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha
CHECK_AND_ASSERT_MES(r, false, "Failed to validate attachments in tx " << tx_prefix_hash << ": incorrect extra_attachment_info in tx.extra");
}
CHECK_AND_ASSERT_MES(check_tx_explicit_asset_id_rules(tx, all_tx_ins_have_explicit_asset_ids), false, "tx does not comply with explicit asset id rules");
CHECK_AND_ASSERT_MES(check_tx_explicit_asset_id_rules(tx, all_tx_ins_have_explicit_native_asset_ids), false, "tx does not comply with explicit asset id rules");
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_attachment_check);
return true;
@ -5074,7 +5331,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
}
//------------------------------------------------------------------
bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash,
uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_asset_ids) const
uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_native_asset_ids) const
{
CRITICAL_REGION_LOCAL(m_read_lock);
@ -5107,8 +5364,8 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index,
for(auto& zc_out : scan_contex.zc_outs)
{
ring.emplace_back(zc_out.stealth_address, zc_out.amount_commitment, zc_out.blinded_asset_id);
if (all_tx_ins_have_explicit_asset_ids && crypto::point_t(zc_out.blinded_asset_id).modify_mul8().to_public_key() != native_coin_asset_id)
all_tx_ins_have_explicit_asset_ids = false;
if (all_tx_ins_have_explicit_native_asset_ids && crypto::point_t(zc_out.blinded_asset_id).modify_mul8().to_public_key() != native_coin_asset_id)
all_tx_ins_have_explicit_native_asset_ids = false;
}
// calculate corresponding tx prefix hash
@ -5587,9 +5844,12 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
return false;
}
size_t count_ado = 0;
//extra
for (const auto el : tx.extra)
{
if (el.type() == typeid(asset_descriptor_operation))
count_ado++;
if (!var_is_after_hardfork_1_zone && !is_allowed_before_hardfork1(el))
return false;
if (!var_is_after_hardfork_2_zone && !is_allowed_before_hardfork2(el))
@ -5614,18 +5874,38 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti
// TODO @#@# consider: 1) tx.proofs, 2) new proof data structures
if (var_is_after_hardfork_4_zone)
{
{
CHECK_AND_ASSERT_MES(tx.version > TRANSACTION_VERSION_PRE_HF4, false, "HF4: tx with version " << tx.version << " is not allowed");
CHECK_AND_ASSERT_MES(tx.vout.size() >= CURRENCY_TX_MIN_ALLOWED_OUTS, false, "HF4: tx.vout has " << tx.vout.size() << " element(s), while required minimum is " << CURRENCY_TX_MIN_ALLOWED_OUTS);
if (is_pos_miner_tx(tx))
CHECK_AND_ASSERT_MES(tx.vout.size() == 1 || tx.vout.size() >= CURRENCY_TX_MIN_ALLOWED_OUTS, false, "HF4: tx.vout has " << tx.vout.size() << " element(s), while 1 or >= " << CURRENCY_TX_MIN_ALLOWED_OUTS << " is expected for a PoS miner tx");
else
CHECK_AND_ASSERT_MES(tx.vout.size() >= CURRENCY_TX_MIN_ALLOWED_OUTS, false, "HF4: tx.vout has " << tx.vout.size() << " element(s), while required minimum is " << CURRENCY_TX_MIN_ALLOWED_OUTS);
if(!validate_inputs_sorting(tx))
{
return false;
}
bool mode_separate = get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE? true:false;
if (is_coinbase(tx) && mode_separate)
{
LOG_ERROR("TX_FLAG_SIGNATURE_MODE_SEPARATE not allowed for coinbase tx");
return false;
}
if (count_ado > 1)
{
LOG_ERROR("More then 1 asset_descriptor_operation not allowed in tx");
return false;
}
if (mode_separate && count_ado > 0)
{
LOG_ERROR("asset_descriptor_operation not allowed in tx with TX_FLAG_SIGNATURE_MODE_SEPARATE");
return false;
}
}
return true;
}
//------------------------------------------------------------------
@ -5697,10 +5977,12 @@ bool blockchain_storage::validate_pos_block(const block& b,
CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key) || b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "incorrect input 1 type: " << b.miner_tx.vin[1].type().name());
const crypto::key_image& stake_key_image = get_key_image_from_txin_v(b.miner_tx.vin[1]);
//check keyimage if it's main chain candidate
TIME_MEASURE_START_PD(pos_validate_ki_search);
if (!for_altchain)
{
CHECK_AND_ASSERT_MES(!have_tx_keyimg_as_spent(stake_key_image), false, "stake key image has been already spent in blockchain: " << stake_key_image);
}
TIME_MEASURE_FINISH_PD(pos_validate_ki_search);
if (!is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM))
{
@ -5735,8 +6017,10 @@ bool blockchain_storage::validate_pos_block(const block& b,
CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1, false, "incorrect number of stake input signatures: " << b.miner_tx.signatures.size());
CHECK_AND_ASSERT_MES(b.miner_tx.signatures[0].type() == typeid(zarcanum_sig), false, "incorrect sig 0 type: " << b.miner_tx.signatures[0].type().name());
//std::stringstream ss;
if (!for_altchain)
{
TIME_MEASURE_START_PD(pos_validate_get_out_keys_for_inputs);
// do general input check for main chain blocks only
// TODO @#@#: txs in alternative PoS blocks (including miner_tx) must be validated by validate_alt_block_txs()
const zarcanum_sig& sig = boost::get<zarcanum_sig>(b.miner_tx.signatures[0]);
@ -5745,11 +6029,25 @@ bool blockchain_storage::validate_pos_block(const block& b,
uint64_t dummy_source_max_unlock_time_for_pos_coinbase_dummy = 0; // won't be used
scan_for_keys_context scan_contex = AUTO_VAL_INIT(scan_contex);
r = get_output_keys_for_input_with_checks(b.miner_tx, stake_input, dummy_output_keys, max_related_block_height, dummy_source_max_unlock_time_for_pos_coinbase_dummy, scan_contex);
//#define ADD_ITEM_TO_SS(item) ss << " " #item ": " << m_performance_data.item.get_last_val() << ENDL
// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_get_item_size);
// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute);
// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop);
// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop_iteration);
// ss << " tx_check_inputs_loop_scan_outputkeys_loop_iteration (avg): " << m_performance_data.tx_check_inputs_loop_scan_outputkeys_loop_iteration.get_avg() << ENDL;
// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop_get_subitem);
// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop_find_tx);
// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
//#undef ADD_ITEM_TO_SS
CHECK_AND_ASSERT_MES(r, false, "get_output_keys_for_input_with_checks failed for stake input");
CHECK_AND_ASSERT_MES(scan_contex.zc_outs.size() == stake_input.key_offsets.size(), false, "incorrect number of referenced outputs found: " << scan_contex.zc_outs.size() << ", while " << stake_input.key_offsets.size() << " is expected.");
// make sure that all referring inputs are either older then, or the same age as, the most resent PoW block.
CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_block_height, false, "stake input refs' max related block height is " << max_related_block_height << " while last PoW block height is " << last_pow_block_height);
TIME_MEASURE_FINISH_PD(pos_validate_get_out_keys_for_inputs);
// build a ring of references
vector<crypto::CLSAG_GGXXG_input_ref_t> ring;
ring.reserve(scan_contex.zc_outs.size());
@ -5759,8 +6057,12 @@ bool blockchain_storage::validate_pos_block(const block& b,
crypto::scalar_t last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, sm.last_pow_id);
uint8_t err = 0;
TIME_MEASURE_START_PD(pos_validate_zvp);
r = crypto::zarcanum_verify_proof(id, kernel_hash, ring, last_pow_block_id_hashed, stake_input.k_image, basic_diff, sig, &err);
TIME_MEASURE_FINISH_PD(pos_validate_zvp);
CHECK_AND_ASSERT_MES(r, false, "zarcanum_verify_proof failed with code " << (int)err);
//std::stringstream ss;
//std::cout << " validate_pos_block > get_output_keys_for_input_with_checks: " << ENDL << ss.str();
}
return true;
@ -6214,7 +6516,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_time);
tx_total_inputs_processing_time += tx_check_inputs_time;
tx_total_inputs_count++;
tx_total_inputs_count += tx.vin.size();
burned_coins += get_burned_amount(tx);
TIME_MEASURE_START_PD(tx_prapare_append);
@ -6265,6 +6567,8 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
if (!m_is_in_checkpoint_zone)
{
// validate_miner_transaction will check balance proof and asset surjection proof
// and, as a side effect, it MAY recalculate base_reward, consider redisign, TODO -- sowle
TIME_MEASURE_START_PD(validate_miner_transaction_time);
if (!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) // TODO @#@# base_reward will be calculated once again, consider refactoring
{
@ -6345,11 +6649,12 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
bvc.m_verification_failed = true;
return false;
}
bei.cumulative_diff_adjusted += cumulative_diff_delta;
//this used only in pre-hardfork 1
bei.cumulative_diff_adjusted += cumulative_diff_delta;
//////////////////////////////////////////////////////////////////////////
// rebuild cumulative_diff_precise_adjusted for whole period
// cumulative_diff_precise_adjusted - native cumulative difficulty adjusted ONLY by sequence_factor
wide_difficulty_type diff_precise_adj = correct_difficulty_with_sequence_factor(sequence_factor, current_diffic);
bei.cumulative_diff_precise_adjusted = last_x_h ? m_db_blocks[last_x_h]->cumulative_diff_precise_adjusted + diff_precise_adj : diff_precise_adj;
@ -6364,6 +6669,10 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
return false;
}
bei.already_generated_coins = already_generated_coins - burned_coins + base_reward;
if (bei.bl.miner_tx.version >= TRANSACTION_VERSION_POST_HF4)
{
bei.already_generated_coins -= fee_summary;
}
auto blocks_index_ptr = m_db_blocks_index.get(id);
if (blocks_index_ptr)
@ -6414,7 +6723,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
TIME_MEASURE_FINISH_PD_MS(block_processing_time_0_ms);
//print result
stringstream powpos_str_entry, timestamp_str_entry;
stringstream powpos_str_entry, timestamp_str_entry, pos_validation_str_entry;
if (is_pos_bl)
{ // PoS
int64_t actual_ts = get_block_datetime(bei.bl); // signed int is intentionally used here
@ -6428,6 +6737,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
else
powpos_str_entry << "hidden";
timestamp_str_entry << ", actual ts: " << actual_ts << " (diff: " << std::showpos << ts_diff << "s) block ts: " << std::noshowpos << bei.bl.timestamp << " (shift: " << std::showpos << static_cast<int64_t>(bei.bl.timestamp) - actual_ts << ")";
pos_validation_str_entry << "(" << m_performance_data.pos_validate_ki_search.get_last_val() << "/" << m_performance_data.pos_validate_get_out_keys_for_inputs.get_last_val() << "/" << m_performance_data.pos_validate_zvp.get_last_val() << ")";
}
else
{ // PoW
@ -6442,23 +6752,41 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt
LOG_PRINT_L1("+++++ BLOCK SUCCESSFULLY ADDED " << (is_pos_bl ? "[PoS]" : "[PoW]") << "["<< static_cast<uint64_t>(bei.bl.major_version) << "." << static_cast<uint64_t>(bei.bl.minor_version) << "] "<< " Sq: " << sequence_factor
<< ENDL << "id:\t" << id << timestamp_str_entry.str()
<< ENDL << powpos_str_entry.str()
<< ENDL << "HEIGHT " << bei.height << ", difficulty: " << current_diffic << ", cumul_diff_precise: " << bei.cumulative_diff_precise << ", cumul_diff_adj: " << bei.cumulative_diff_adjusted << " (+" << cumulative_diff_delta << ")"
<< ENDL << "HEIGHT " << bei.height << ", difficulty: " << current_diffic << ", cumul_diff_precise: " << bei.cumulative_diff_precise << ", cumul_diff_precise_adj: " << bei.cumulative_diff_precise_adjusted << " (+" << cumulative_diff_delta << ")"
<< ENDL << "block reward: " << print_money_brief(base_reward + fee_summary) << " (" << print_money_brief(base_reward) << " + " << print_money_brief(fee_summary)
<< ")" << ", coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size << ", tx_count: " << bei.bl.tx_hashes.size()
<< ", timing: " << block_processing_time_0_ms << "ms"
<< "(micrsec:" << block_processing_time_1
<< "(" << target_calculating_time_2 << "(" << m_performance_data.target_calculating_enum_blocks.get_last_val() << "/" << m_performance_data.target_calculating_calc.get_last_val() << ")"
<< "/" << longhash_calculating_time_3
<< "/" << longhash_calculating_time_3 << pos_validation_str_entry.str()
<< "/" << insert_time_4
<< "/" << all_txs_insert_time_5
<< "/" << etc_stuff_6
<< "/" << tx_total_inputs_processing_time << " of " << tx_total_inputs_count
<< "/(" << m_performance_data.validate_miner_transaction_time.get_last_val() << "|"
<< m_performance_data.collect_rangeproofs_data_from_tx_time.get_last_val() << "|"
<< m_performance_data.verify_multiple_zc_outs_range_proofs_time.get_last_val()
<< m_performance_data.verify_multiple_zc_outs_range_proofs_time.get_last_val() << "~"
<< range_proofs_agregated.size()
<< ")"
<< "))");
{
static epee::math_helper::average<uint64_t, 30> blocks_processing_time_avg_pos, blocks_processing_time_avg_pow;
(is_pos_bl ? blocks_processing_time_avg_pos : blocks_processing_time_avg_pow).push(block_processing_time_0_ms);
static std::deque<uint64_t> blocks_processing_time_median_pos, blocks_processing_time_median_pow;
std::deque<uint64_t>& d = (is_pos_bl ? blocks_processing_time_median_pos : blocks_processing_time_median_pow);
d.push_back(block_processing_time_0_ms);
if (d.size() > 200)
d.pop_front();
uint64_t median_pow = epee::misc_utils::median(blocks_processing_time_median_pow);
uint64_t median_pos = epee::misc_utils::median(blocks_processing_time_median_pos);
LOG_PRINT_YELLOW("last 30 blocks of type processing time (ms): PoW: " << std::setw(3) << (uint64_t)blocks_processing_time_avg_pow.get_avg() << ", PoS: " << (uint64_t)blocks_processing_time_avg_pos.get_avg(), LOG_LEVEL_1);
LOG_PRINT_YELLOW("last 200 blocks of type processing time (median, ms): PoW: " << std::setw(3) << median_pow << ", PoS: " << median_pos, LOG_LEVEL_1);
}
on_block_added(bei, id, block_summary_kimages);
bvc.m_added_to_main_chain = true;
@ -7023,8 +7351,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
CRITICAL_REGION_LOCAL(m_read_lock);
bool r = false;
if (p_max_related_block_height != nullptr)
*p_max_related_block_height = 0;
uint64_t max_related_block_height = 0;
CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size(), false, "invalid input index: " << input_index);
@ -7271,7 +7598,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
const txout_to_key& out_tk = boost::get<txout_to_key>(t);
pk = out_tk.key;
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(out_tk.mix_attr, abs_key_offsets.size() - 1);
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(p->tx.version, out_tk.mix_attr, abs_key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(mixattr_ok, false, "input offset #" << pk_n << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(out_tk.mix_attr) << ", input's key_offsets.size = " << abs_key_offsets.size());
}
@ -7285,8 +7612,8 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
// case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid)
CHECK_AND_ASSERT_MES(p->m_keeper_block_height < split_height, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height);
if (p_max_related_block_height != nullptr && *p_max_related_block_height < p->m_keeper_block_height)
*p_max_related_block_height = p->m_keeper_block_height;
if (max_related_block_height < p->m_keeper_block_height)
max_related_block_height = p->m_keeper_block_height;
// TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks()
// make sure it was actually found
@ -7332,6 +7659,20 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx,
VARIANT_SWITCH_END();
if (p_max_related_block_height != nullptr)
*p_max_related_block_height = max_related_block_height;
uint64_t alt_bl_h = split_height + alt_chain.size() + 1;
if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, alt_bl_h))
{
if (alt_bl_h - max_related_block_height < CURRENCY_HF4_MANDATORY_MIN_COINAGE)
{
LOG_ERROR("Coinage rule broken(altblock): h = " << alt_bl_h << ", max_related_block_height=" << max_related_block_height << ", tx: " << input_tx_hash);
return false;
}
}
// TODO: consider checking input_tx for valid extra attachment info as it's checked in check_tx_inputs()
return true;
}
@ -7648,6 +7989,7 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
CHECK_AND_ASSERT_MES(validate_tx_for_hardfork_specific_terms(b.miner_tx, null_hash, height), false, "miner tx hardfork-specific validation failed");
std::vector<uint64_t> fees;
for (auto tx_id : b.tx_hashes)
{
std::shared_ptr<transaction> tx_ptr;
@ -7659,6 +8001,9 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
const transaction& tx = it == abei.onboard_transactions.end() ? *tx_ptr : it->second;
CHECK_AND_ASSERT_MES(tx.signatures.size() == tx.vin.size(), false, "invalid tx: signatures.size() == " << tx.signatures.size() << ", tx.vin.size() == " << tx.vin.size());
fees.push_back(get_tx_fee(tx));
for (size_t n = 0; n < tx.vin.size(); ++n)
{
if (tx.vin[n].type() == typeid(txin_to_key) || tx.vin[n].type() == typeid(txin_htlc) || tx.vin[n].type() == typeid(txin_zc_input))
@ -7691,6 +8036,7 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha
update_alt_out_indexes_for_tx_in_block(tx, abei);
}
abei.this_block_tx_fee_median = epee::misc_utils::median(fees);
return true;
}

View file

@ -77,6 +77,11 @@ namespace currency
epee::math_helper::average<uint64_t, 5> target_calculating_enum_blocks;
epee::math_helper::average<uint64_t, 5> target_calculating_calc;
//longhash_calculating_time_3
epee::math_helper::average<uint64_t, 1> pos_validate_ki_search;
epee::math_helper::average<uint64_t, 1> pos_validate_get_out_keys_for_inputs;
epee::math_helper::average<uint64_t, 1> pos_validate_zvp;
//tx processing zone
epee::math_helper::average<uint64_t, 1> tx_check_inputs_time;
epee::math_helper::average<uint64_t, 1> tx_add_one_tx_time;
@ -281,6 +286,7 @@ namespace currency
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp)const;
bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const;
bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const;
bool get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const;
bool get_backward_blocks_sizes(size_t from_height, std::vector<size_t>& sz, size_t count)const;
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs)const;
bool get_alias_info(const std::string& alias, extra_alias_entry_base& info)const;
@ -298,7 +304,7 @@ namespace currency
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, bool& tx_has_explicit_asset_ids_in_all_ins) const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_native_asset_ids) const;
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height)const;
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash) const;
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id)const;
@ -324,6 +330,7 @@ namespace currency
boost::multiprecision::uint128_t total_coins()const;
bool is_pos_allowed()const;
uint64_t get_tx_fee_median()const;
uint64_t get_tx_fee_window_value_median() const;
uint64_t get_tx_expiration_median() const;
uint64_t validate_alias_reward(const transaction& tx, const std::string& ai)const;
void set_event_handler(i_core_event_handler* event_handler) const;
@ -584,8 +591,8 @@ namespace currency
mutable std::atomic<bool> m_deinit_is_done;
mutable uint64_t m_blockchain_launch_timestamp;
bool init_tx_fee_median();
bool update_tx_fee_median();
//bool init_tx_fee_median();
//bool update_tx_fee_median();
void store_db_solo_options_values();
bool set_lost_tx_unmixable();
bool set_lost_tx_unmixable_for_height(uint64_t height);
@ -636,6 +643,8 @@ namespace currency
bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector<uint64_t>& global_indexes);
bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id);
bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false, uint64_t height_upper_limit = 0) const;
bool get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map<uint64_t, uint64_t>& amounts_to_up_index_limit_cache) const;
bool get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map<uint64_t, uint64_t>& amounts_to_up_index_limit_cache) const;
bool add_block_as_invalid(const block& bl, const crypto::hash& h);
bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h);
size_t find_end_of_allowed_index(uint64_t amount)const;
@ -650,6 +659,7 @@ namespace currency
uint64_t get_tx_fee_median_effective_index(uint64_t h) const;
void on_abort_transaction();
void load_targetdata_cache(bool is_pos) const;
uint64_t get_adjusted_time()const;
@ -732,6 +742,8 @@ namespace currency
template<class visitor_t>
bool blockchain_storage::scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& verified_input, visitor_t& vis, uint64_t& max_related_block_height, scan_for_keys_context& scan_context) const
{
bool hf4 = this->is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM);
uint64_t amount = get_amount_from_variant(verified_input);
const std::vector<txout_ref_v>& key_offsets = get_key_offsets_from_txin_v(verified_input);
@ -747,7 +759,7 @@ namespace currency
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute);
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop);
size_t output_index = 0;
for(const txout_ref_v& o : absolute_offsets)
for (const txout_ref_v& o : absolute_offsets)
{
crypto::hash tx_id = null_hash;
size_t n = 0;
@ -802,8 +814,13 @@ namespace currency
//fix for burned money
patch_out_if_needed(const_cast<txout_to_key&>(outtk), tx_id, n);
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(outtk.mix_attr, key_offsets.size() - 1);
CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx input ref #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(outtk.mix_attr) << ", key_offsets.size = " << key_offsets.size());
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, outtk.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast<uint32_t>(outtk.mix_attr) << ", key_offsets.size = " << key_offsets.size());
if (hf4)
{
bool legit_output_key = validate_output_key_legit(outtk.key);
CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << outtk.key);
}
}
else if (o.target.type() == typeid(txout_htlc))
{
@ -823,6 +840,12 @@ namespace currency
//HTLC IS expired, can be used ONLY by pkey_after_expiration and ONLY by to_key input
scan_context.htlc_is_expired = true;
}
if (hf4)
{
bool legit_output_key = validate_output_key_legit(scan_context.htlc_is_expired ? htlc_out.pkey_refund : htlc_out.pkey_redeem);
CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << static_cast<const crypto::public_key&>(scan_context.htlc_is_expired ? htlc_out.pkey_refund : htlc_out.pkey_redeem));
}
}
else
{
@ -842,19 +865,23 @@ namespace currency
}
VARIANT_CASE_CONST(tx_out_zarcanum, out_zc)
bool r = is_output_allowed_for_input(out_zc, verified_input);
CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible");
CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible");
r = is_mixattr_applicable_for_fake_outs_counter(out_zc.mix_attr, key_offsets.size() - 1);
CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size());
r = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, out_zc.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast<uint32_t>(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size());
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n))
{
size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin();
LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx));
return false;
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
bool legit_output_key = validate_output_key_legit(out_zc.stealth_address);
CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << out_zc.stealth_address);
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n))
{
size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin();
LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx));
return false;
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
VARIANT_CASE_THROW_ON_OTHER();
VARIANT_SWITCH_END();
@ -862,9 +889,22 @@ namespace currency
if (max_related_block_height < tx_ptr->m_keeper_block_height)
max_related_block_height = tx_ptr->m_keeper_block_height;
++output_index;
}
if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, this->get_current_blockchain_size()))
{
//with hard fork 4 make it network rule to have at least 10 confirmations
if (this->get_current_blockchain_size() - max_related_block_height < CURRENCY_HF4_MANDATORY_MIN_COINAGE)
{
LOG_ERROR("Coinage rule broken(mainblock): h = " << this->get_current_blockchain_size() << ", max_related_block_height=" << max_related_block_height << ", tx: " << get_transaction_hash(validated_tx));
return false;
}
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop);
return true;
}

View file

@ -48,9 +48,9 @@ namespace currency
block bl;
uint64_t height;
uint64_t block_cumulative_size;
wide_difficulty_type cumulative_diff_adjusted;
wide_difficulty_type cumulative_diff_adjusted; // used only before hardfork 1
wide_difficulty_type cumulative_diff_precise;
wide_difficulty_type cumulative_diff_precise_adjusted;
wide_difficulty_type cumulative_diff_precise_adjusted; //used after hardfork 1 (cumulative difficulty adjusted only by sequence factor)
wide_difficulty_type difficulty;
boost::multiprecision::uint128_t already_generated_coins;
crypto::hash stake_hash; //TODO: unused field for PoW blocks, subject for refactoring
@ -148,6 +148,7 @@ namespace currency
uint64_t height;
tx_generation_context miner_tx_tgc; // bad design, a lot of copying, consider redesign -- sowle
uint64_t block_reward_without_fee;
uint64_t block_reward; // == block_reward_without_fee + txs_fee if fees are given to the miner, OR block_reward_without_fee if fees are burnt
uint64_t txs_fee; // sum of transactions' fee if any
};

View file

@ -27,6 +27,7 @@ namespace currency
ADD_CHECKPOINT(1161000, "96990d851b484e30190678756ba2a4d3a2f92b987e2470728ac1e38b2bf35908");
ADD_CHECKPOINT(1480000, "5dd3381eec35e8b4eba4518bfd8eec682a4292761d92218fd59b9f0ffedad3fe");
ADD_CHECKPOINT(2000000, "7b6698a8cc279aa78d6263f01fef186bd16f5b1ea263a7f4714abc1d506b9cb3");
ADD_CHECKPOINT(2390000, "10797d34349d0ef1d1ab4b41ada6f8f2c2f86a7f7eebe44dd2ba06067cb47e0a");
#endif
return true;

View file

@ -105,6 +105,7 @@ namespace currency
uint64_t max_alt_blocks;
crypto::public_key alias_validation_pubkey;
core_time_func_t get_core_time;
uint64_t hf4_minimum_mixins;
hard_forks_descriptor hard_forks;
@ -127,6 +128,7 @@ namespace currency
pc.tx_pool_min_fee = TX_MINIMUM_FEE;
pc.tx_default_fee = TX_DEFAULT_FEE;
pc.max_alt_blocks = CURRENCY_ALT_BLOCK_MAX_COUNT;
pc.hf4_minimum_mixins = CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE;
// TODO: refactor the following
pc.hard_forks.set_hardfork_height(1, ZANO_HARDFORK_01_AFTER_HEIGHT);

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2023 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Copyright (c) 2014-2015 The Boolberry developers
@ -60,7 +60,7 @@ namespace currency
// Using C++17 extended aggregate initialization (P0017R1). C++17, finally! -- sowle
const static crypto::public_key native_coin_asset_id = {{'\xd6', '\x32', '\x9b', '\x5b', '\x1f', '\x7c', '\x08', '\x05', '\xb5', '\xc3', '\x45', '\xf4', '\x95', '\x75', '\x54', '\x00', '\x2a', '\x2f', '\x55', '\x78', '\x45', '\xf6', '\x4d', '\x76', '\x45', '\xda', '\xe0', '\xe0', '\x51', '\xa6', '\x49', '\x8a'}}; // == crypto::c_point_H, checked in crypto_constants
const static crypto::public_key native_coin_asset_id_1div8 = {{'\x74', '\xc3', '\x2d', '\x3e', '\xaa', '\xfa', '\xfc', '\x62', '\x3b', '\xf4', '\x83', '\xe8', '\x58', '\xd4', '\x2e', '\x8b', '\xf4', '\xec', '\x7d', '\xf0', '\x64', '\xad', '\xa2', '\xe3', '\x49', '\x34', '\x46', '\x9c', '\xff', '\x6b', '\x62', '\x68'}}; // == 1/8 * crypto::c_point_H, checked in crypto_constants
const static crypto::point_t native_coin_asset_id_pt = crypto::c_point_H;
const static crypto::point_t native_coin_asset_id_pt {{ 20574939, 16670001, -29137604, 14614582, 24883426, 3503293, 2667523, 420631, 2267646, -4769165, -11764015, -12206428, -14187565, -2328122, -16242653, -788308, -12595746, -8251557, -10110987, 853396, -4982135, 6035602, -21214320, 16156349, 977218, 2807645, 31002271, 5694305, -16054128, 5644146, -15047429, -568775, -22568195, -8089957, -27721961, -10101877, -29459620, -13359100, -31515170, -6994674 }}; // c_point_H
const static wide_difficulty_type global_difficulty_pow_starter = DIFFICULTY_POW_STARTER;
const static wide_difficulty_type global_difficulty_pos_starter = DIFFICULTY_POS_STARTER;
@ -315,51 +315,6 @@ namespace currency
/////////////////////////////////////////////////////////////////////////////
// Zarcanum structures
//
//#pragma pack(push, 1)
/*
struct zarcanum_input : public referring_input
{
zarcanum_input() {}
// Boost's Assignable concept
zarcanum_input(const zarcanum_input&) = default;
zarcanum_input& operator=(const zarcanum_input&)= default;
crypto::key_image k_image;
BEGIN_SERIALIZE_OBJECT()
FIELD(k_image)
FIELD(key_offsets) // referring_input
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(k_image)
BOOST_SERIALIZE(key_offsets) // referring_input
END_BOOST_SERIALIZATION()
};
// txin_zarcanum_inputs contains several zarcanum_input instances and corresponds to one ZC_sig
struct txin_zarcanum_inputs
{
txin_zarcanum_inputs() {}
// Boost's Assignable concept
txin_zarcanum_inputs(const txin_zarcanum_inputs&) = default;
txin_zarcanum_inputs& operator=(const txin_zarcanum_inputs&) = default;
std::vector<zarcanum_input> elements;
std::vector<txin_etc_details_v> etc_details;
BEGIN_SERIALIZE_OBJECT()
FIELD(elements)
FIELD(etc_details)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(elements)
BOOST_SERIALIZE(etc_details)
END_BOOST_SERIALIZATION()
};
*/
struct txin_zc_input : public referring_input
{
@ -816,15 +771,15 @@ namespace currency
{
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
asset_descriptor_base descriptor;
boost::optional<crypto::public_key> opt_amount_commitment; // premultiplied by 1/8
boost::optional<crypto::signature> opt_proof; // operation proof - for update/emit
boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
crypto::public_key amount_commitment; // premultiplied by 1/8
boost::optional<crypto::signature> opt_proof; // operation proof - for update/emit
boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER;
BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER, verion)
FIELD(operation_type)
FIELD(descriptor)
FIELD(opt_amount_commitment)
FIELD(amount_commitment)
END_VERSION_UNDER(1)
FIELD(opt_proof)
FIELD(opt_asset_id)
@ -833,7 +788,7 @@ namespace currency
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(operation_type)
BOOST_SERIALIZE(descriptor)
BOOST_SERIALIZE(opt_amount_commitment)
BOOST_SERIALIZE(amount_commitment)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(opt_proof)
BOOST_SERIALIZE(opt_asset_id)

View file

@ -10,7 +10,7 @@
#ifndef TESTNET
#define CURRENCY_FORMATION_VERSION 84
#else
#define CURRENCY_FORMATION_VERSION 89
#define CURRENCY_FORMATION_VERSION 94
#endif
#define CURRENCY_GENESIS_NONCE (CURRENCY_FORMATION_VERSION + 101011010121) //bender's nightmare
@ -37,6 +37,8 @@
#define CURRENT_BLOCK_MAJOR_VERSION 3
#define CURRENCY_DEFAULT_DECOY_SET_SIZE 10
#define CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE 15
#define CURRENCY_HF4_MANDATORY_MIN_COINAGE 10
#define CURRENT_BLOCK_MINOR_VERSION 0
#define CURRENCY_BLOCK_FUTURE_TIME_LIMIT 60*60*2
@ -164,6 +166,8 @@
#define BLOCK_POS_STRICT_SEQUENCE_LIMIT 20 // the highest allowed sequence factor for a PoS block (i.e., the max total number of sequential PoS blocks is BLOCK_POS_STRICT_SEQUENCE_LIMIT + 1)
#define CORE_FEE_BLOCKS_LOOKUP_WINDOW 60 //number of blocks used to check if transaction flow is big enought to rise default fee
#define WALLET_FILE_SIGNATURE_OLD 0x1111012101101011LL // Bender's nightmare
#define WALLET_FILE_SIGNATURE_V2 0x1111011201101011LL // another Bender's nightmare
#define WALLET_FILE_BINARY_HEADER_VERSION_INITAL 1000
@ -246,8 +250,8 @@
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
#ifndef TESTNET
#define WALLET_FILE_SERIALIZATION_VERSION 160
#define WALLET_FILE_LAST_SUPPORTED_VERSION 160
#define WALLET_FILE_SERIALIZATION_VERSION 161
#define WALLET_FILE_LAST_SUPPORTED_VERSION 161
#else
#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+76)
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+76)
@ -265,11 +269,11 @@
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577
#define ZANO_HARDFORK_04_AFTER_HEIGHT 999999999
#else
/////// Zarcanum Testnet Pre-Alpha //////////////////////////////
/////// Zarcanum Testnet //////////////////////////////
#define ZANO_HARDFORK_01_AFTER_HEIGHT 0
#define ZANO_HARDFORK_02_AFTER_HEIGHT 0
#define ZANO_HARDFORK_03_AFTER_HEIGHT 0
#define ZANO_HARDFORK_04_AFTER_HEIGHT 1440
#define ZANO_HARDFORK_04_AFTER_HEIGHT 2440
#endif

View file

@ -116,7 +116,7 @@ namespace currency
secret_index = ring.size() - 1;
}
CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": can't find a corresponding asset id in inputs");
CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": can't find a corresponding asset id in inputs, asset id: " << H);
result.bge_proofs.emplace_back(crypto::BGE_proof_s{});
uint8_t err = 0;
@ -129,7 +129,6 @@ namespace currency
//--------------------------------------------------------------------------------
bool verify_asset_surjection_proof(const transaction& tx, const crypto::hash& tx_id)
{
bool r = false;
if (tx.version <= TRANSACTION_VERSION_PRE_HF4)
return true;
@ -362,15 +361,19 @@ namespace currency
const account_public_address &stakeholder_address,
transaction& tx,
uint64_t& block_reward_without_fee,
uint64_t& block_reward,
uint64_t tx_version,
const blobdata& extra_nonce /* = blobdata() */,
size_t max_outs /* = CURRENCY_MINER_TX_MAX_OUTS */,
bool pos /* = false */,
const pos_entry& pe /* = pos_entry() */, // only pe.stake_unlock_time and pe.stake_amount are used now, TODO: consider refactoring -- sowle
tx_generation_context* ogc_ptr /* = nullptr */,
const keypair* tx_one_time_key_to_use /* = nullptr */
const keypair* tx_one_time_key_to_use /* = nullptr */,
const std::vector<tx_destination_entry>& destinations_ /* = std::vector<tx_destination_entry>() */
)
{
std::vector<tx_destination_entry> destinations = destinations_;
bool r = false;
if (!get_block_reward(pos, median_size, current_block_size, already_generated_coins, block_reward_without_fee, height))
@ -378,45 +381,56 @@ namespace currency
LOG_ERROR("Block is too big");
return false;
}
uint64_t block_reward = block_reward_without_fee + fee;
block_reward = block_reward_without_fee;
// before HF4: add tx fee to the block reward; after HF4: burn it
if (tx_version < TRANSACTION_VERSION_POST_HF4)
{
block_reward += fee;
}
//
// prepare destinations
//
// 1. split block_reward into out_amounts
std::vector<uint64_t> out_amounts;
if (tx_version > TRANSACTION_VERSION_PRE_HF4)
if (!destinations.size())
{
// randomly split into CURRENCY_TX_MIN_ALLOWED_OUTS outputs
decompose_amount_randomly(block_reward, [&](uint64_t a){ out_amounts.push_back(a); }, CURRENCY_TX_MIN_ALLOWED_OUTS);
}
else
{
// non-hidden outs: split into digits
decompose_amount_into_digits(block_reward, DEFAULT_DUST_THRESHOLD,
[&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); },
[&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
while (max_outs < out_amounts.size())
//
// prepare destinations
//
// 1. split block_reward into out_amounts
std::vector<uint64_t> out_amounts;
if (tx_version > TRANSACTION_VERSION_PRE_HF4)
{
out_amounts[out_amounts.size() - 2] += out_amounts.back();
out_amounts.resize(out_amounts.size() - 1);
// randomly split into CURRENCY_TX_MIN_ALLOWED_OUTS outputs for PoW block, or for PoS block only if the stakeholder address differs
// (otherwise for PoS miner tx there will be ONE output with amount = stake_amount + reward)
if (!pos || miner_address != stakeholder_address)
decompose_amount_randomly(block_reward, [&](uint64_t a) { out_amounts.push_back(a); }, CURRENCY_TX_MIN_ALLOWED_OUTS);
}
}
// 2. construct destinations using out_amounts
std::vector<tx_destination_entry> destinations;
for (auto a : out_amounts)
{
tx_destination_entry de = AUTO_VAL_INIT(de);
de.addr.push_back(miner_address);
de.amount = a;
de.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
else
{
//this means that block is creating after hardfork_1 and unlock_time is needed to set for every destination separately
de.unlock_time = height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW;
// non-hidden outs: split into digits
decompose_amount_into_digits(block_reward, DEFAULT_DUST_THRESHOLD,
[&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); },
[&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
while (max_outs < out_amounts.size())
{
out_amounts[out_amounts.size() - 2] += out_amounts.back();
out_amounts.resize(out_amounts.size() - 1);
}
}
// 2. construct destinations using out_amounts
for (auto a : out_amounts)
{
tx_destination_entry de = AUTO_VAL_INIT(de);
de.addr.push_back(miner_address);
de.amount = a;
de.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
{
//this means that block is creating after hardfork_1 and unlock_time is needed to set for every destination separately
de.unlock_time = height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW;
}
destinations.push_back(de);
}
destinations.push_back(de);
}
if (pos)
@ -424,7 +438,8 @@ namespace currency
uint64_t stake_lock_time = 0;
if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW)
stake_lock_time = pe.stake_unlock_time;
destinations.push_back(tx_destination_entry(pe.amount, stakeholder_address, stake_lock_time));
uint64_t amount = destinations.empty() ? pe.amount + block_reward : pe.amount; // combine stake and reward into one output if no destinations were generated above
destinations.push_back(tx_destination_entry(amount, stakeholder_address, stake_lock_time));
destinations.back().flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is
}
@ -547,16 +562,16 @@ namespace currency
if (additional_inputs_amount_and_fees_for_mining_tx == 0)
{
// normal tx
CHECK_AND_ASSERT_MES(bare_inputs_sum >= bare_outputs_sum, false, "tx balance error: sum of inputs (" << print_money_brief(bare_inputs_sum)
<< ") is less than or equal to sum of outputs(" << print_money_brief(bare_outputs_sum) << ")");
CHECK_AND_ASSERT_MES(bare_inputs_sum >= bare_outputs_sum, false, "tx balance error: the sum of inputs (" << print_money_brief(bare_inputs_sum)
<< ") is less than or equal to the sum of outputs (" << print_money_brief(bare_outputs_sum) << ")");
}
else
{
// miner tx
CHECK_AND_ASSERT_MES(bare_inputs_sum + additional_inputs_amount_and_fees_for_mining_tx == bare_outputs_sum, false,
"tx balance error: sum of inputs (" << print_money_brief(bare_inputs_sum) <<
"tx balance error: the sum of inputs (" << print_money_brief(bare_inputs_sum) <<
") + additional inputs and fees (" << print_money_brief(additional_inputs_amount_and_fees_for_mining_tx) <<
") is less than or equal to sum of outputs(" << print_money_brief(bare_outputs_sum) << ")");
") is less than or equal to the sum of outputs (" << print_money_brief(bare_outputs_sum) << ")");
}
return true;
}
@ -575,9 +590,8 @@ namespace currency
else
{
// make sure that amount commitment corresponds to opt_amount_commitment_g_proof
CHECK_AND_ASSERT_MES(context.ado.opt_amount_commitment.has_value(), false, "opt_amount_commitment is absent");
CHECK_AND_ASSERT_MES(aop.opt_amount_commitment_g_proof.has_value(), false, "opt_amount_commitment_g_proof is absent");
crypto::point_t A = crypto::point_t(context.ado.opt_amount_commitment.get()).modify_mul8() - context.amount_to_validate * context.asset_id_pt;
crypto::point_t A = crypto::point_t(context.ado.amount_commitment).modify_mul8() - context.amount_to_validate * context.asset_id_pt;
bool r = crypto::check_signature(context.tx_id, A.to_public_key(), aop.opt_amount_commitment_g_proof.get());
CHECK_AND_ASSERT_MES(r, false, "opt_amount_commitment_g_proof check failed");
@ -632,13 +646,11 @@ namespace currency
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT)
{
// opt_amount_commitment supposed to be validated earlier in validate_asset_operation()
CHECK_AND_ASSERT_MES(ado.opt_amount_commitment.has_value(), false, "opt_amount_commitment is not set");
sum_of_pseudo_out_amount_commitments += crypto::point_t(ado.opt_amount_commitment.get()); // *1/8
sum_of_pseudo_out_amount_commitments += crypto::point_t(ado.amount_commitment); // *1/8
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
CHECK_AND_ASSERT_MES(ado.opt_amount_commitment.has_value(), false, "opt_amount_commitment is not set");
outs_commitments_sum += crypto::point_t(ado.opt_amount_commitment.get()); // *1/8
outs_commitments_sum += crypto::point_t(ado.amount_commitment); // *1/8
}
}
size_t zc_sigs_count = 0;
@ -725,14 +737,24 @@ namespace currency
return total;
}
//---------------------------------------------------------------
bool is_mixattr_applicable_for_fake_outs_counter(uint8_t mix_attr, uint64_t fake_outputs_count)
bool is_mixattr_applicable_for_fake_outs_counter(uint64_t out_tx_version, uint8_t mix_attr, uint64_t fake_outputs_count, const core_runtime_config& rtc)
{
if (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND)
return fake_outputs_count + 1 >= mix_attr;
else if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
return fake_outputs_count == 0;
if (out_tx_version >= TRANSACTION_VERSION_POST_HF4)
{
if (mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
return fake_outputs_count >= rtc.hf4_minimum_mixins;
else
return fake_outputs_count == 0; // CURRENCY_TO_KEY_OUT_FORCED_NO_MIX
}
else
return true;
{
if (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND)
return fake_outputs_count + 1 >= mix_attr;
else if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX)
return fake_outputs_count == 0;
else
return true;
}
}
//---------------------------------------------------------------
bool parse_amount(uint64_t& amount, const std::string& str_amount_)
@ -2093,7 +2115,7 @@ namespace currency
{
crypto::hash h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, asset_owner);
// this hash function needs to be computationally expensive (s.e. the whitepaper)
// this hash function needs to be computationally expensive (s.a. the whitepaper)
for(uint64_t i = 0; i < CRYPTO_HASH_ASSET_ID_ITERATIONS; ++i)
h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, h, i);
@ -2127,21 +2149,20 @@ namespace currency
bool construct_tx_handle_ado(const account_keys& sender_account_keys,
const finalize_tx_param& ftp,
asset_descriptor_operation& ado,
tx_generation_context& gen_context,
const crypto::secret_key& one_time_tx_secret_key,
tx_generation_context& gen_context,
const keypair& tx_key,
std::vector<tx_destination_entry>& shuffled_dsts)
{
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER)
{
//CHECK_AND_ASSERT_MES(ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER, false, "unsupported asset operation: " << (int)ado.operation_type);
crypto::secret_key asset_control_key{};
bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, one_time_tx_secret_key, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, tx_key.sec, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed");
calculate_asset_id(ado.descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id);
// calculate amount blinding mask
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, asset_control_key);
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, asset_control_key, tx_key.pub);
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0;
@ -2156,23 +2177,18 @@ namespace currency
ado.descriptor.current_supply = amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle
gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
ado.opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
else {
else
{
if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT)
{
//bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, one_time_tx_secret_key, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY);
//CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed");
//calculate_asset_id(ado.descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id);
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT/UPDATE");
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT");
gen_context.ao_asset_id = *ado.opt_asset_id;
gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id);
// calculate amount blinding mask
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key);
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key, tx_key.pub);
// set correct asset_id to the corresponding destination entries
uint64_t amount_of_emitted_asset = 0;
@ -2184,30 +2200,27 @@ namespace currency
item.asset_id = gen_context.ao_asset_id;
}
}
ado.descriptor.current_supply += amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle
ado.descriptor.current_supply += amount_of_emitted_asset;
gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
ado.opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE)
{
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT/UPDATE");
//CHECK_AND_ASSERT_MES(ado.opt_proof, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMMIT/UPDATE");
CHECK_AND_ASSERT_MES(!ado.opt_amount_commitment, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT/UPDATE");
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE");
//CHECK_AND_ASSERT_MES(ado.opt_proof, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE");
//fields that not supposed to be changed?
}
else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN)
{
//calculate_asset_id(ado.descriptor.owner, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id);
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT/UPDATE");
CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN");
gen_context.ao_asset_id = *ado.opt_asset_id;
gen_context.ao_asset_id_pt.from_public_key(gen_context.ao_asset_id);
// calculate amount blinding mask
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key);
gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, ftp.asset_control_key, tx_key.pub);
gen_context.ao_commitment_in_outputs = true;
// set correct asset_id to the corresponding destination entries
@ -2227,10 +2240,10 @@ namespace currency
amount_of_burned_assets -= item.amount;
}
}
ado.descriptor.current_supply -= amount_of_burned_assets; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle
ado.descriptor.current_supply -= amount_of_burned_assets;
gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G;
ado.opt_amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key();
}
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_seal{ &ado });
@ -2497,7 +2510,7 @@ namespace currency
pado = get_type_in_variant_container<asset_descriptor_operation>(tx.extra);
if (pado)
{
bool r = construct_tx_handle_ado(sender_account_keys, ftp, *pado, gen_context, one_time_tx_secret_key, shuffled_dsts);
bool r = construct_tx_handle_ado(sender_account_keys, ftp, *pado, gen_context, txkey, shuffled_dsts);
CHECK_AND_ASSERT_MES(r, false, "Failed to construct_tx_handle_ado()");
if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation{ pado });
}
@ -3317,9 +3330,15 @@ namespace currency
att.push_back(tsa);
return true;
}
//---------------------------------------------------------------
bool validate_output_key_legit(const crypto::public_key& k)
{
if (currency::null_pkey == k)
{
return false;
}
return true;
}
//---------------------------------------------------------------
std::string print_money_brief(uint64_t amount, size_t decimal_point /* = CURRENCY_DISPLAY_DECIMAL_POINT */)
{
@ -4041,11 +4060,7 @@ namespace currency
//-----------------------------------------------------------------------
bool is_pos_coinbase(const transaction& tx)
{
bool pos = false;
if (!is_coinbase(tx, pos) || !pos)
return false;
return true;
return is_pos_miner_tx(tx);
}
//-----------------------------------------------------------------------
bool is_coinbase(const transaction& tx, bool& pos_coinbase)
@ -4053,7 +4068,7 @@ namespace currency
if (!is_coinbase(tx))
return false;
pos_coinbase = (tx.vin.size() == 2 && tx.vin[1].type() == typeid(txin_to_key));
pos_coinbase = is_pos_coinbase(tx);
return true;
}
//-----------------------------------------------------------------------
@ -4429,8 +4444,6 @@ namespace currency
a.k_image == b.k_image;
}
//--------------------------------------------------------------------------------
boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty(const wide_difficulty_type& difficulty_pos_at_split_point,
const wide_difficulty_type& difficulty_pow_at_split_point,
const difficulties& a_diff,
@ -4463,6 +4476,51 @@ namespace currency
return res;
CATCH_ENTRY_WITH_FORWARDING_EXCEPTION();
}
//--------------------------------------------------------------------------------
// Note: we adjust formula and introduce multiplier,
// that let us never dive into floating point calculations (which we can't use in consensus)
// this multiplier should be greater than max multiprecision::uint128_t power 2
boost::multiprecision::uint1024_t get_adjuster_for_fork_choice_rule_hf4()
{
return boost::multiprecision::uint1024_t(std::numeric_limits<boost::multiprecision::uint128_t>::max()) * 10 * std::numeric_limits<boost::multiprecision::uint128_t>::max();
}
const boost::multiprecision::uint1024_t adjusting_multiplier = get_adjuster_for_fork_choice_rule_hf4();
boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty_hf4(const wide_difficulty_type& difficulty_pos_at_split_point,
const wide_difficulty_type& difficulty_pow_at_split_point,
const difficulties& a_diff,
const difficulties& b_diff)
{
static const wide_difficulty_type difficulty_pos_starter = DIFFICULTY_POS_STARTER;
static const wide_difficulty_type difficulty_pow_starter = DIFFICULTY_POW_STARTER;
const wide_difficulty_type& a_pos_cumulative_difficulty = a_diff.pos_diff > 0 ? a_diff.pos_diff : difficulty_pos_starter;
const wide_difficulty_type& b_pos_cumulative_difficulty = b_diff.pos_diff > 0 ? b_diff.pos_diff : difficulty_pos_starter;
const wide_difficulty_type& a_pow_cumulative_difficulty = a_diff.pow_diff > 0 ? a_diff.pow_diff : difficulty_pow_starter;
const wide_difficulty_type& b_pow_cumulative_difficulty = b_diff.pow_diff > 0 ? b_diff.pow_diff : difficulty_pow_starter;
boost::multiprecision::uint1024_t basic_sum_ = boost::multiprecision::uint1024_t(a_pow_cumulative_difficulty) + (boost::multiprecision::uint1024_t(a_pos_cumulative_difficulty)*difficulty_pow_at_split_point) / difficulty_pos_at_split_point;
boost::multiprecision::uint1024_t basic_sum_pow_minus2 = adjusting_multiplier /(basic_sum_ * basic_sum_);
boost::multiprecision::uint1024_t res =
(basic_sum_pow_minus2 * a_pow_cumulative_difficulty * a_pos_cumulative_difficulty) / (boost::multiprecision::uint1024_t(b_pow_cumulative_difficulty)*b_pos_cumulative_difficulty);
// if (res > boost::math::tools::max_value<wide_difficulty_type>())
// {
// ASSERT_MES_AND_THROW("[INTERNAL ERROR]: Failed to get_a_to_b_relative_cumulative_difficulty, res = " << res << ENDL
// << ", difficulty_pos_at_split_point: " << difficulty_pos_at_split_point << ENDL
// << ", difficulty_pow_at_split_point:" << difficulty_pow_at_split_point << ENDL
// << ", a_pos_cumulative_difficulty:" << a_pos_cumulative_difficulty << ENDL
// << ", b_pos_cumulative_difficulty:" << b_pos_cumulative_difficulty << ENDL
// << ", a_pow_cumulative_difficulty:" << a_pow_cumulative_difficulty << ENDL
// << ", b_pow_cumulative_difficulty:" << b_pow_cumulative_difficulty << ENDL
// );
// }
TRY_ENTRY();
// wide_difficulty_type short_res = res.convert_to<wide_difficulty_type>();
return res;
CATCH_ENTRY_WITH_FORWARDING_EXCEPTION();
}

View file

@ -274,13 +274,16 @@ namespace currency
const account_public_address &stakeholder_address,
transaction& tx,
uint64_t& block_reward_without_fee,
uint64_t& block_reward,
uint64_t tx_version,
const blobdata& extra_nonce = blobdata(),
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
bool pos = false,
const pos_entry& pe = pos_entry(),
tx_generation_context* ogc_ptr = nullptr,
const keypair* tx_one_time_key_to_use = nullptr);
const keypair* tx_one_time_key_to_use = nullptr,
const std::vector<tx_destination_entry>& destinations = std::vector<tx_destination_entry>()
);
//---------------------------------------------------------------
uint64_t get_string_uint64_hash(const std::string& str);
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, crypto::scalar_t& asset_blinding_mask, crypto::scalar_t& amount_blinding_mask, crypto::point_t& blinded_asset_id, crypto::point_t& amount_commitment, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
@ -362,7 +365,7 @@ namespace currency
tx_derivation_hint make_tx_derivation_hint_from_uint16(uint16_t hint);
std::string short_hash_str(const crypto::hash& h);
bool is_mixattr_applicable_for_fake_outs_counter(uint8_t mix_attr, uint64_t fake_attr_count);
bool is_mixattr_applicable_for_fake_outs_counter(uint64_t out_tx_version, uint8_t out_mix_attr, uint64_t fake_outputs_count, const core_runtime_config& rtc);
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time);
crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys);
bool decrypt_payload_items(bool is_income, const transaction& tx, const account_keys& acc_keys, std::vector<payload_items_v>& decrypted_items);
@ -407,7 +410,7 @@ namespace currency
std::vector<txout_ref_v> relative_output_offsets_to_absolute(const std::vector<txout_ref_v>& off);
bool absolute_sorted_output_offsets_to_relative_in_place(std::vector<txout_ref_v>& offsets) noexcept;
bool validate_output_key_legit(const crypto::public_key& k);
// prints amount in format "3.14", "0.0"
std::string print_money_brief(uint64_t amount, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT);
@ -421,6 +424,7 @@ namespace currency
bool add_padding_to_tx(transaction& tx, size_t count);
bool is_service_tx(const transaction& tx);
bool does_tx_have_only_mixin_inputs(const transaction& tx);
uint64_t get_hf4_inputs_key_offsets_count(const transaction& tx);
bool is_showing_sender_addres(const transaction& tx);
bool check_native_coins_amount_burnt_in_outs(const transaction& tx, const uint64_t amount, uint64_t* p_amount_burnt = nullptr);
std::string print_stake_kernel_info(const stake_kernel& sk);
@ -933,6 +937,13 @@ namespace currency
const difficulties& b_diff
);
boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty_hf4(const wide_difficulty_type& difficulty_pos_at_split_point,
const wide_difficulty_type& difficulty_pow_at_split_point,
const difficulties& a_diff,
const difficulties& b_diff
);
struct rpc_tx_payload_handler : public boost::static_visitor<bool>
{
tx_extra_rpc_entry& tv;

View file

@ -404,7 +404,7 @@ namespace currency
#ifdef TESTNET
return true;
#else
return false;
return true;
#endif
}

View file

@ -21,6 +21,7 @@
#include "crypto/hash.h"
#include "profile_tools.h"
#include "common/db_backend_selector.h"
#include "tx_semantic_validation.h"
DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated
@ -92,6 +93,15 @@ namespace currency
return true;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::check_tx_fee(const transaction &tx, uint64_t amount_fee)
{
if (amount_fee < m_blockchain.get_core_runtime_config().tx_pool_min_fee)
return false;
//m_blockchain.get
return true;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::add_tx(const transaction &tx, const crypto::hash &id, uint64_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool from_core)
{
bool r = false;
@ -158,20 +168,31 @@ namespace currency
//check key images for transaction if it is not kept by block
if(!from_core && !kept_by_block)
{
if(!validate_tx_semantic(tx, blob_size))
{
// tx semantics check failed
LOG_PRINT_RED_L0("Transaction " << id << " semantics check failed ");
tvc.m_verification_failed = true;
tvc.m_should_be_relayed = false;
tvc.m_added_to_pool = false;
return false;
}
crypto::key_image spent_ki = AUTO_VAL_INIT(spent_ki);
r = !have_tx_keyimges_as_spent(tx, &spent_ki);
CHECK_AND_ASSERT_MES(r, false, "Transaction " << id << " uses already spent key image " << spent_ki);
//transaction spam protection, soft rule
if (tx_fee < m_blockchain.get_core_runtime_config().tx_pool_min_fee)
if (!check_tx_fee(tx, tx_fee))
{
if (is_valid_contract_finalization_tx(tx))
{
//if (is_valid_contract_finalization_tx(tx))
//{
// that means tx has less fee then allowed by current tx pull rules, but this transaction is actually
// a finalization of contract, and template of this contract finalization tx was prepared actually before
// fee rules had been changed, so it's ok, let it in.
}
else
//}
//else
{
// this tx has no fee
LOG_PRINT_RED_L0("Transaction " << id << " has too small fee: " << print_money_brief(tx_fee) << ", minimum fee: " << print_money_brief(m_blockchain.get_core_runtime_config().tx_pool_min_fee));

View file

@ -145,6 +145,7 @@ namespace currency
bool remove_key_images(const crypto::hash &tx_id, const transaction& tx, bool kept_by_block);
bool insert_alias_info(const transaction& tx);
bool remove_alias_info(const transaction& tx);
bool check_tx_fee(const transaction &tx, uint64_t amount_fee);
bool is_valid_contract_finalization_tx(const transaction &tx)const;
void store_db_solo_options_values();

View file

@ -1939,6 +1939,17 @@ QString MainWindow::restore_wallet(const QString& param)
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::use_whitelisting(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
//return que_call2<view::restore_wallet_request>("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){
PREPARE_ARG_FROM_JSON(view::api_request_t<bool>, owd);
PREPARE_RESPONSE(view::api_responce_return_code, ar);
ar.error_code = m_backend.use_whitelisting(owd.wallet_id, owd.req_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::open_wallet(const QString& param)
{
TRY_ENTRY();

View file

@ -144,6 +144,7 @@ public:
QString webkit_launched_script();
QString get_smart_wallet_info(const QString& param);
QString restore_wallet(const QString& param);
QString use_whitelisting(const QString& param);
QString is_pos_allowed();
QString store_to_file(const QString& path, const QString& buff);
QString load_from_file(const QString& path);

@ -1 +1 @@
Subproject commit c5687a8f1a7195f11e707c465419ee9b8d6ebd92
Subproject commit 18cb69f348bae38186f3a8da8bc9fc9991d38cd1

View file

@ -117,6 +117,13 @@ namespace currency
res.default_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_default_fee;
res.minimum_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_pool_min_fee;
auto & hf = m_core.get_blockchain_storage().get_core_runtime_config().hard_forks.m_height_the_hardfork_n_active_after;
res.is_hardfok_active.resize(hf.size());
for (size_t i = 0; i != hf.size(); i++)
{
res.is_hardfok_active[i] = m_core.get_blockchain_storage().is_hardfork_active(i);
}
//conditional values
if (req.flags&COMMAND_RPC_GET_INFO_FLAG_NET_TIME_DELTA_MEDIAN)
{
@ -384,6 +391,18 @@ namespace currency
return true;
}
bool core_rpc_server::on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx)
{
CHECK_CORE_READY();
res.status = API_RETURN_CODE_FAIL;
if (!m_core.get_blockchain_storage().get_random_outs_for_amounts2(req, res))
{
return true;
}
res.status = API_RETURN_CODE_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res, connection_context& cntx)
{
@ -931,6 +950,7 @@ namespace currency
res.miner_tx_tgc = resp.miner_tx_tgc;
res.height = resp.height;
res.block_reward_without_fee = resp.block_reward_without_fee;
res.block_reward = resp.block_reward;
res.txs_fee = resp.txs_fee;
//calculate epoch seed
res.seed = currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(res.height));

View file

@ -49,6 +49,7 @@ namespace currency
bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx);
bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx);
bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx);
bool on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx);
bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx);
bool on_set_maintainers_info(const COMMAND_RPC_SET_MAINTAINERS_INFO::request& req, COMMAND_RPC_SET_MAINTAINERS_INFO::response& res, connection_context& cntx);
bool on_get_tx_pool(const COMMAND_RPC_GET_TX_POOL::request& req, COMMAND_RPC_GET_TX_POOL::response& res, connection_context& cntx);
@ -109,6 +110,7 @@ namespace currency
MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST)
MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES)
MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS)
MAP_URI_AUTO_BIN2("/getrandom_outs2.bin", on_get_random_outs2, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2)
MAP_URI_AUTO_BIN2("/set_maintainers_info.bin", on_set_maintainers_info, COMMAND_RPC_SET_MAINTAINERS_INFO)
MAP_URI_AUTO_BIN2("/get_tx_pool.bin", on_get_tx_pool, COMMAND_RPC_GET_TX_POOL)
MAP_URI_AUTO_BIN2("/check_keyimages.bin", on_check_keyimages, COMMAND_RPC_CHECK_KEYIMAGES)
@ -141,6 +143,7 @@ namespace currency
MAP_JON_RPC ("get_all_pool_tx_list", on_get_all_pool_tx_list, COMMAND_RPC_GET_ALL_POOL_TX_LIST)
MAP_JON_RPC ("get_pool_info", on_get_pool_info, COMMAND_RPC_GET_POOL_INFO)
MAP_JON_RPC ("getrandom_outs", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS)
MAP_JON_RPC ("getrandom_outs2", on_get_random_outs2, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2)
MAP_JON_RPC ("get_votes", on_get_votes, COMMAND_RPC_GET_VOTES)
//assets api
MAP_JON_RPC ("get_asset_info", on_get_asset_info, COMMAND_RPC_GET_ASSET_INFO)

View file

@ -422,6 +422,42 @@ namespace currency
};
};
//-----------------------------------------------
struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2
{
struct offsets_distribution
{
uint64_t amount; //if amount is 0 then lookup in post-zarcanum zone only, if not 0 then pre-zarcanum only
std::vector<uint64_t> offsets; //[i] = height, estimated location where to pickup output of transaction
uint64_t own_global_index; //index to exclude from selection
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE(offsets)
KV_SERIALIZE(own_global_index)
END_KV_SERIALIZE_MAP()
};
struct request
{
std::vector<offsets_distribution> amounts;
uint64_t height_upper_limit; // if nonzero, all the decoy outputs must be either older than, or the same age as this height
bool use_forced_mix_outs;
uint64_t coinbase_percents; //from 0 to 100, estimate percents of coinbase outputs included in decoy sets
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amounts)
KV_SERIALIZE(height_upper_limit)
KV_SERIALIZE(use_forced_mix_outs)
KV_SERIALIZE(coinbase_percents)
END_KV_SERIALIZE_MAP()
};
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response response;
};
//-----------------------------------------------
struct COMMAND_RPC_SET_MAINTAINERS_INFO
{
@ -757,6 +793,7 @@ namespace currency
uint64_t minimum_fee;
uint64_t last_block_timestamp;
std::string last_block_hash;
std::vector<bool> is_hardfok_active;
//market
uint64_t offers_count;
@ -807,6 +844,7 @@ namespace currency
KV_SERIALIZE(minimum_fee)
KV_SERIALIZE(last_block_timestamp)
KV_SERIALIZE(last_block_hash)
KV_SERIALIZE(is_hardfok_active)
KV_SERIALIZE(offers_count)
END_KV_SERIALIZE_MAP()
};
@ -889,6 +927,7 @@ namespace currency
std::string prev_hash;
tx_generation_context miner_tx_tgc;
uint64_t block_reward_without_fee;
uint64_t block_reward; // == block_reward_without_fee + txs_fee if fees are given to the miner, OR block_reward_without_fee if fees are burnt
uint64_t txs_fee;
std::string status;
@ -900,6 +939,7 @@ namespace currency
KV_SERIALIZE(prev_hash)
KV_SERIALIZE(miner_tx_tgc)
KV_SERIALIZE(block_reward_without_fee)
KV_SERIALIZE(block_reward)
KV_SERIALIZE(txs_fee)
KV_SERIALIZE(status)
END_KV_SERIALIZE_MAP()

View file

@ -116,7 +116,7 @@ namespace ph = boost::placeholders;
fail_msg_writer() << "unknown error"; \
} \
#define CONFIRM_WITH_PASSWORD() if(!check_password_for_operation()) return true;
namespace
@ -140,6 +140,7 @@ namespace
const command_line::arg_descriptor<bool> arg_disable_tor_relay ( "disable-tor-relay", "Disable TOR relay", false);
const command_line::arg_descriptor<unsigned int> arg_set_timeout("set-timeout", "Set timeout for the wallet");
const command_line::arg_descriptor<std::string> arg_voting_config_file("voting-config-file", "Set voting config instead of getting if from daemon", "");
const command_line::arg_descriptor<bool> arg_no_password_confirmations("no-password-confirmation", "Enable/Disable password confirmation for transactions", false);
const command_line::arg_descriptor< std::vector<std::string> > arg_command ("command", "");
@ -445,6 +446,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_do_refresh_after_load = false;
}
m_password_salt = crypto::rand<uint64_t>();
m_password_hash = get_hash_from_pass_and_salt(pwd_container.password(), m_password_salt);
bool was_open = false;
if (!m_generate_new.empty())
{
@ -516,6 +520,12 @@ bool simple_wallet::deinit()
return close_wallet();
}
//----------------------------------------------------------------------------------------------------
crypto::hash simple_wallet::get_hash_from_pass_and_salt(const std::string& pass, uint64_t salt)
{
std::string pass_and_salt = pass + std::to_string(salt);
return crypto::cn_fast_hash(pass_and_salt.data(), pass_and_salt.size());
}
//----------------------------------------------------------------------------------------------------
void simple_wallet::handle_command_line(const boost::program_options::variables_map& vm)
{
m_wallet_file = command_line::get_arg(vm, arg_wallet_file);
@ -529,8 +539,36 @@ void simple_wallet::handle_command_line(const boost::program_options::variables_
m_restore_wallet = command_line::get_arg(vm, arg_restore_wallet);
m_disable_tor = command_line::get_arg(vm, arg_disable_tor_relay);
m_voting_config_file = command_line::get_arg(vm, arg_voting_config_file);
m_no_password_confirmations = command_line::get_arg(vm, arg_no_password_confirmations);
}
//----------------------------------------------------------------------------------------------------
#define PASSWORD_CONFIRMATION_ATTEMPTS 3
bool simple_wallet::check_password_for_operation()
{
if (m_no_password_confirmations)
return true;
for (size_t i = 0; i != PASSWORD_CONFIRMATION_ATTEMPTS; i++)
{
tools::password_container pass_container;
if (!pass_container.read_password("Enter password to confirm operation:\n"))
{
fail_msg_writer() << "Failed to read password";
return false;
}
if (get_hash_from_pass_and_salt(pass_container.password(), m_password_salt) != m_password_hash)
{
fail_msg_writer() << "Wrong password";
continue;
}
return true;
}
fail_msg_writer() << "Confirmation failed with " << PASSWORD_CONFIRMATION_ATTEMPTS << " attempts";
return false;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::try_connect_to_daemon()
{
if (!m_wallet->check_connection())
@ -1529,6 +1567,7 @@ bool preprocess_asset_id(std::string& address_arg, crypto::public_key& asset_id)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::transfer(const std::vector<std::string> &args_)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (!try_connect_to_daemon())
return true;
@ -1692,6 +1731,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
//----------------------------------------------------------------------------------------------------
bool simple_wallet::show_seed(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
success_msg_writer() << "Please enter a password to secure this seed. Securing your seed is HIGHLY recommended. Leave password blank to stay unsecured.";
success_msg_writer(true) << "Remember, restoring a wallet from Secured Seed can only be done if you know its password.";
@ -1715,6 +1755,7 @@ bool simple_wallet::show_seed(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::spendkey(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
message_writer(epee::log_space::console_color_red, true, std::string())
<< "WARNING! Anyone who knows the following secret key can access your wallet and spend your coins.";
@ -1727,6 +1768,7 @@ bool simple_wallet::spendkey(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::viewkey(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
message_writer(epee::log_space::console_color_yellow, false, std::string())
<< "WARNING! Anyone who knows the following secret key can view your wallet (but can not spend your coins).";
@ -1924,6 +1966,7 @@ bool simple_wallet::list_outputs(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sign_transfer(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
if (m_wallet->is_watch_only())
{
fail_msg_writer() << "You can't sign transaction in watch-only wallet";
@ -1997,6 +2040,7 @@ bool simple_wallet::tor_disable(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::deploy_new_asset(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
asset_descriptor_base adb = AUTO_VAL_INIT(adb);
if (!args.size() || args.size() > 1)
@ -2034,7 +2078,7 @@ bool simple_wallet::deploy_new_asset(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::emit_asset(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (args.size() != 2)
{
@ -2089,6 +2133,7 @@ bool simple_wallet::emit_asset(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::burn_asset(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (args.size() != 2)
{
@ -2137,6 +2182,7 @@ bool simple_wallet::burn_asset(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::update_asset(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (args.size() != 2)
{
@ -2186,6 +2232,7 @@ bool simple_wallet::update_asset(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::add_custom_asset_id(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (!args.size() || args.size() > 1)
{
@ -2221,6 +2268,7 @@ bool simple_wallet::add_custom_asset_id(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::generate_ionic_swap_proposal(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (args.size() != 2)
@ -2309,6 +2357,7 @@ bool simple_wallet::get_ionic_swap_proposal_info(const std::vector<std::string>
//----------------------------------------------------------------------------------------------------
bool simple_wallet::accept_ionic_swap_proposal(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (args.size() != 1)
@ -2350,6 +2399,7 @@ bool simple_wallet::accept_ionic_swap_proposal(const std::vector<std::string> &a
//----------------------------------------------------------------------------------------------------
bool simple_wallet::remove_custom_asset_id(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
if (!args.size() || args.size() > 1)
{
@ -2380,6 +2430,7 @@ bool simple_wallet::remove_custom_asset_id(const std::vector<std::string> &args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::sweep_below(const std::vector<std::string> &args)
{
CONFIRM_WITH_PASSWORD();
SIMPLE_WALLET_BEGIN_TRY_ENTRY();
bool r = false;
if (args.size() < 3 || args.size() > 4)
@ -2623,6 +2674,8 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_disable_tor_relay);
command_line::add_arg(desc_params, arg_set_timeout);
command_line::add_arg(desc_params, arg_voting_config_file);
command_line::add_arg(desc_params, arg_no_password_confirmations);

View file

@ -110,6 +110,8 @@ namespace currency
bool try_connect_to_daemon();
std::string get_tocken_info_string(const crypto::public_key& asset_id, uint64_t& decimal_point);
bool print_wti(const tools::wallet_public::wallet_transfer_info& wti);
bool check_password_for_operation();
crypto::hash get_hash_from_pass_and_salt(const std::string& pass, uint64_t salt);
//----------------- i_wallet2_callback ---------------------
virtual void on_new_block(uint64_t height, const currency::block& block) override;
@ -189,6 +191,10 @@ namespace currency
bool m_disable_tor;
std::string m_restore_wallet;
std::string m_voting_config_file;
bool m_no_password_confirmations = false;
crypto::hash m_password_hash;
uint64_t m_password_salt;
epee::console_handlers_binder m_cmd_binder;

View file

@ -8,6 +8,6 @@
#define PROJECT_REVISION "0"
#define PROJECT_VERSION PROJECT_MAJOR_VERSION "." PROJECT_MINOR_VERSION "." PROJECT_REVISION
#define PROJECT_VERSION_BUILD_NO 244
#define PROJECT_VERSION_BUILD_NO 253
#define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO)
#define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]"

View file

@ -77,6 +77,11 @@ namespace tools
return invoke_http_bin_remote_command2_update_is_disconnect("/getrandom_outs.bin", req, res);
}
//------------------------------------------------------------------------------------------------------------------------------
bool default_http_core_proxy::call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)
{
return invoke_http_bin_remote_command2_update_is_disconnect("/getrandom_outs2.bin", req, res);
}
//------------------------------------------------------------------------------------------------------------------------------
bool default_http_core_proxy::call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& req, currency::COMMAND_RPC_SEND_RAW_TX::response& res)
{
return invoke_http_json_remote_command2_update_is_disconnect("/sendrawtransaction", req, res);

View file

@ -37,6 +37,7 @@ namespace tools
bool call_COMMAND_RPC_GET_TX_POOL(const currency::COMMAND_RPC_GET_TX_POOL::request& rqt, currency::COMMAND_RPC_GET_TX_POOL::response& rsp) override;
bool call_COMMAND_RPC_GET_ALIASES_BY_ADDRESS(const currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& rqt, currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& rsp) override;
bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& rsp) override;
bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& rsp) override;
bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& rqt, currency::COMMAND_RPC_SEND_RAW_TX::response& rsp) override;
bool call_COMMAND_RPC_FORCE_RELAY_RAW_TXS(const currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& rqt, currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& rsp) override;
bool call_COMMAND_RPC_GET_ALL_ALIASES(currency::COMMAND_RPC_GET_ALL_ALIASES::response& rsp) override;

View file

@ -58,6 +58,11 @@ namespace tools
return m_rpc.on_get_random_outs(req, res, m_cntxt_stub);
}
//------------------------------------------------------------------------------------------------------------------------------
bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res) override
{
return m_rpc.on_get_random_outs2(req, res, m_cntxt_stub);
}
//------------------------------------------------------------------------------------------------------------------------------
bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& req, currency::COMMAND_RPC_SEND_RAW_TX::response& res) override
{
return m_rpc.on_send_raw_tx(req, res, m_cntxt_stub);

View file

@ -36,6 +36,7 @@ namespace tools
virtual bool call_COMMAND_RPC_GET_TX_POOL(const currency::COMMAND_RPC_GET_TX_POOL::request& rqt, currency::COMMAND_RPC_GET_TX_POOL::response& rsp){ return false; }
virtual bool call_COMMAND_RPC_GET_ALIASES_BY_ADDRESS(const currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& rqt, currency::COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& rsp){ return false; }
virtual bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& rsp){ return false; }
virtual bool call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(const currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& rqt, currency::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& rsp) { return false; }
virtual bool call_COMMAND_RPC_SEND_RAW_TX(const currency::COMMAND_RPC_SEND_RAW_TX::request& rqt, currency::COMMAND_RPC_SEND_RAW_TX::response& rsp){ return false; }
virtual bool call_COMMAND_RPC_FORCE_RELAY_RAW_TXS(const currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& rqt, currency::COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& rsp){ return false; }
virtual bool call_COMMAND_RPC_GET_ALL_ALIASES(currency::COMMAND_RPC_GET_ALL_ALIASES::response& rsp){ return false; }

View file

@ -0,0 +1,128 @@
// Copyright (c) 2014-2023 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "decoy_selection.h"
#include "decoy_selection_default_distribution.hpp"
#include "crypto/crypto.h"
bool scaler::config_scale(uint64_t original, uint64_t scale_to)
{
m_x_m = original;
m_y_m = scale_to;
return true;
}
uint64_t scaler::scale(uint64_t h)
{
double k = double(m_x_m) / m_y_m;
double e_pow_minus_k = std::exp(-1 * k);
double a = e_pow_minus_k / (k - 1 + e_pow_minus_k);
double y = h * a + (1 - std::exp(-1 * (double(h) / double(m_y_m)) )) * m_y_m * (1 - a);
return static_cast<uint64_t>(std::round(y));
}
void decoy_selection_generator::init(uint64_t max_h)
{
load_distribution(g_default_distribution, max_h);
m_is_initialized = true;
}
bool decoy_selection_generator::load_distribution_from_file(const char* path)
{
return true;
}
#define TWO63 0x8000000000000000u
#define TWO64f (TWO63*2.0)
double map_uint_to_double(uint64_t u) {
double y = (double)u;
return y / TWO64f;
}
std::vector<uint64_t> decoy_selection_generator::generate_distribution(uint64_t count)
{
std::vector<uint64_t> res;
for (size_t i = 0; i != count; i++)
{
uint64_t r = 0;
crypto::generate_random_bytes(sizeof(r), &r);
double r_ = map_uint_to_double(r);
auto it = m_distribution_mapping.upper_bound(r_);
if (it == m_distribution_mapping.end())
{
throw(std::runtime_error(std::string("_r not found in m_distribution_mapping: ") + std::to_string(r_) ));
}
uint64_t h = it->second;
if (it != m_distribution_mapping.begin())
{
uint64_t h_0 = (--it)->second;
crypto::generate_random_bytes(sizeof(r), &r);
h = h_0 + r % (h - h_0) + 1;
}
//scale from nominal to max_h
res.push_back(h); }
return res;
}
uint64_t get_distance(const std::vector<decoy_selection_generator::distribution_entry> entries, size_t i)
{
if (i == 0)
return 1;
return entries[i].h - entries[i - 1].h;
}
bool decoy_selection_generator::load_distribution(const std::vector<decoy_selection_generator::distribution_entry>& original_distribution, uint64_t max_h)
{
//do prescale of distribution
std::vector<decoy_selection_generator::distribution_entry> derived_distribution;
scaler scl;
scl.config_scale(original_distribution.back().h, max_h);
uint64_t last_scaled_h = 0;
std::list<double> last_scaled_array;
for (size_t i = 0; i <= original_distribution.size(); i++)
{
if (i == original_distribution.size() || (scl.scale(original_distribution[i].h) != last_scaled_h && last_scaled_array.size()))
{
//put avg to data_scaled
double summ = 0;
for (auto item: last_scaled_array)
{
summ += item;
}
double avg = summ / last_scaled_array.size();
uint64_t prev_h = scl.scale(original_distribution[i - 1].h);
derived_distribution.push_back(decoy_selection_generator::distribution_entry{ prev_h, avg});
last_scaled_array.clear();
}
if (i == original_distribution.size())
{
break;
}
last_scaled_array.push_back(original_distribution[i].v);
last_scaled_h = scl.scale(original_distribution[i].h);
}
double total_v = 0;
for (size_t i = 0; i != derived_distribution.size(); i++)
{
total_v += derived_distribution[i].v * get_distance(derived_distribution, i);
}
double summ_current = 0;
for (size_t i = 0; i != derived_distribution.size(); i++)
{
double k = (derived_distribution[i].v * get_distance(derived_distribution, i))/ total_v;
summ_current += k;
m_distribution_mapping[summ_current] = derived_distribution[i].h;
}
return true;
}

View file

@ -0,0 +1,53 @@
// Copyright (c) 2014-2023 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <memory>
#include <boost/serialization/list.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/deque.hpp>
#include <boost/serialization/singleton.hpp>
#include <boost/serialization/extended_type_info.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/optional.hpp>
#include <atomic>
#include "include_base_utils.h"
#include "profile_tools.h"
#include "sync_locked_object.h"
class scaler
{
public:
//See the graph on https://www.desmos.com/calculator/zfx4bolfqx
bool config_scale(uint64_t original, uint64_t scale_to);
uint64_t scale(uint64_t h);
private:
uint64_t m_x_m;
uint64_t m_y_m;
};
class decoy_selection_generator
{
public:
struct distribution_entry
{
uint64_t h;
double v;
};
void init(uint64_t max_h);
bool load_distribution_from_file(const char* path);
std::vector<uint64_t> generate_distribution(uint64_t count);
bool is_initialized() { return m_is_initialized; }
private:
bool load_distribution(const std::vector<decoy_selection_generator::distribution_entry>& entries, uint64_t max_h);
bool m_is_initialized = false;
std::map<double, uint64_t> m_distribution_mapping;
};

File diff suppressed because it is too large Load diff

View file

@ -44,6 +44,7 @@ using namespace epee;
#include "currency_core/crypto_config.h"
#include "crypto/zarcanum.h"
#include "wallet_debug_events_definitions.h"
#include "decoy_selection.h"
using namespace currency;
@ -639,8 +640,17 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
auto it = m_key_images.find(ki);
if (it != m_key_images.end())
{
// Issue that has been discovered by Luke Parker (twitter: @kayabaNerve)
// An attacker can quickly issue transaction that use same outputs ephemeral keys + same tx key, as a result both
// transaction's outputs would have same key image, so the wallet should have smart approach to this situation, ie
// use output that offer biggest output value.(tokens?)
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->second < m_transfers.size(), "m_key_images entry has wrong m_transfers index, it->second: " << it->second << ", m_transfers.size(): " << m_transfers.size());
const transfer_details& local_td = m_transfers[it->second];
std::stringstream ss;
ss << "tx " << ptc.tx_hash() << " @ block " << height << " has output #" << o << " with key image " << ki << " that has already been seen in output #" <<
local_td.m_internal_output_index << " in tx " << get_transaction_hash(local_td.m_ptx_wallet_info->m_tx) << " @ block " << local_td.m_spent_height <<
@ -698,7 +708,8 @@ void wallet2::process_new_transaction(const currency::transaction& tx, uint64_t
if (ptc.coin_base_tx)
{
//last out in coinbase tx supposed to be change from coinstake
if (!(o == tx.vout.size() - 1 && !ptc.is_derived_from_coinbase)) // TODO: @#@# reconsider this condition
//for genesis block we'll count every input as WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER
if (td.m_ptx_wallet_info->m_block_height == 0 || !(o == tx.vout.size() - 1 && !ptc.is_derived_from_coinbase)) // TODO: @#@# reconsider this condition
{
td.m_flags |= WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER;
}
@ -3338,7 +3349,16 @@ bool wallet2::balance(std::unordered_map<crypto::public_key, wallet_public::asse
if (is_transfer_unlocked(td))
e.unlocked += td.amount();
if (td.m_flags & WALLET_TRANSFER_DETAIL_FLAG_MINED_TRANSFER)
mined += td.amount();
{
if (td.m_ptx_wallet_info->m_block_height == 0)
{
//for genesis block we add actual amounts
mined += td.amount();
}
else {
mined += CURRENCY_BLOCK_REWARD; //this code would work only for cases where block reward is full. For reduced block rewards might need more flexible code (TODO)
}
}
}
}
@ -3413,10 +3433,13 @@ bool wallet2::balance(std::list<wallet_public::asset_balance_entry>& balances, u
auto it_cust = custom_assets_local.find(item.first);
if(it_cust == custom_assets_local.end())
{
if(!m_use_assets_whitelisting)
continue;
auto it_local = m_whitelisted_assets.find(item.first);
if(it_local == m_whitelisted_assets.end())
if(it_local == m_whitelisted_assets.end())
{
WLT_LOG_YELLOW("WARNING: unknown asset " << item.first << " found and skipped; it's NOT included in balance", LOG_LEVEL_0);
WLT_LOG_YELLOW("WARNING: unknown asset " << item.first << " found and skipped; it's NOT included in balance", LOG_LEVEL_1);
continue;
}
else
@ -3495,7 +3518,7 @@ bool wallet2::add_custom_asset_id(const crypto::public_key& asset_id, asset_desc
req.asset_id = asset_id;
bool r = m_core_proxy->call_COMMAND_RPC_GET_ASSET_INFO(req, resp);
if (resp.status == API_RETURN_CODE_OK)
if (r && resp.status == API_RETURN_CODE_OK)
{
m_custom_assets[asset_id] = resp.asset_descriptor;
asset_descriptor = resp.asset_descriptor;
@ -3636,7 +3659,7 @@ std::string wallet2::get_balance_str() const
balance(balances, mined);
for (const tools::wallet_public::asset_balance_entry& b : balances)
{
ss << " " << std::setw(20) << print_fixed_decimal_point_with_trailing_spaces(b.unlocked, b.asset_info.decimal_point);
ss << " " << std::left << std::setw(20) << print_fixed_decimal_point_with_trailing_spaces(b.unlocked, b.asset_info.decimal_point);
if (b.total == b.unlocked)
ss << " ";
else
@ -4265,7 +4288,7 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, uint64_t ful
uint64_t secret_index = 0; // index of the real stake output
// get decoys outputs and construct miner tx
static size_t required_decoys_count = 4; // TODO @#@# set them somewhere else
const size_t required_decoys_count = m_core_runtime_config.hf4_minimum_mixins == 0 ? 4 /* <-- for tests */ : m_core_runtime_config.hf4_minimum_mixins;
static bool use_only_forced_to_mix = false; // TODO @#@# set them somewhere else
if (required_decoys_count > 0 && !is_auditable())
{
@ -4578,8 +4601,7 @@ bool wallet2::build_minted_block(const mining_context& cxt, const currency::acco
set_block_datetime(current_timestamp, b);
WLT_LOG_MAGENTA("Applying actual timestamp: " << current_timestamp, LOG_LEVEL_2);
uint64_t full_block_reward = tmpl_rsp.block_reward_without_fee + tmpl_rsp.txs_fee;
res = prepare_and_sign_pos_block(cxt, full_block_reward, tmpl_req.pe, tmpl_rsp.miner_tx_tgc, b);
res = prepare_and_sign_pos_block(cxt, tmpl_rsp.block_reward, tmpl_req.pe, tmpl_rsp.miner_tx_tgc, b);
WLT_CHECK_AND_ASSERT_MES(res, false, "Failed to prepare_and_sign_pos_block");
crypto::hash block_hash = get_block_hash(b);
@ -5465,17 +5487,19 @@ bool wallet2::create_ionic_swap_proposal(const wallet_public::ionic_swap_proposa
{
std::vector<uint64_t> selected_transfers_for_template;
build_ionic_swap_template(proposal_details, destination_addr, proposal, selected_transfers_for_template);
return build_ionic_swap_template(proposal_details, destination_addr, proposal, selected_transfers_for_template);
//const uint32_t mask_to_mark_escrow_template_locked_transfers = WALLET_TRANSFER_DETAIL_FLAG_BLOCKED | WALLET_TRANSFER_DETAIL_FLAG_ESCROW_PROPOSAL_RESERVATION;
//mark_transfers_with_flag(selected_transfers_for_template, mask_to_mark_escrow_template_locked_transfers, "preparing ionic_swap");
return true;
//return true;
}
//----------------------------------------------------------------------------------------------------
bool wallet2::build_ionic_swap_template(const wallet_public::ionic_swap_proposal_info& proposal_detais, const currency::account_public_address& destination_addr,
wallet_public::ionic_swap_proposal& proposal,
std::vector<uint64_t>& selected_transfers)
{
WLT_THROW_IF_FALSE_WITH_CODE(proposal_detais.fee_paid_by_a >= get_current_minimum_network_fee(), "Error at build_ionic_swap_template, ", API_RETURN_CODE_WALLET_FEE_TOO_LOW);
construct_tx_param ctp = get_default_construct_tx_param();
ctp.fake_outputs_count = proposal_detais.mixins;
@ -5856,43 +5880,102 @@ void wallet2::prefetch_global_indicies_if_needed(const std::vector<uint64_t>& se
}
}
//----------------------------------------------------------------------------------------------------
bool wallet2::prepare_tx_sources(size_t fake_outputs_count, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies)
bool wallet2::prepare_tx_sources(size_t fake_outputs_count_, std::vector<currency::tx_source_entry>& sources, const std::vector<uint64_t>& selected_indicies)
{
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
typedef currency::tx_source_entry::output_entry tx_output_entry;
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
if (fake_outputs_count)
//we should request even of fake_outputs_count == 0, since for for postzarcanum this era this param is redefined
//todo: remove if(true) block later if this code will be settled
if (true)
{
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request req = AUTO_VAL_INIT(req);
size_t fake_outputs_count = fake_outputs_count_;
uint64_t zarcanum_start_from = m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM];
uint64_t current_size = m_chain.get_blockchain_current_size();
decoy_selection_generator zarcanum_decoy_set_generator;
if (current_size - 1 >= zarcanum_start_from)
{
//in Zarcanum era
const uint64_t test_scale_size = current_size - 1 - zarcanum_start_from;
zarcanum_decoy_set_generator.init(test_scale_size - 1);
}
bool need_to_request = fake_outputs_count != 0;
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request req = AUTO_VAL_INIT(req);
req.height_upper_limit = m_last_pow_block_h; // request decoys to be either older than, or the same age as stake output's height
req.use_forced_mix_outs = false; // TODO: add this feature to UI later
req.decoys_count = fake_outputs_count + 1; // one more to be able to skip a decoy in case it hits the real output
//req.decoys_count = fake_outputs_count + 1; // one more to be able to skip a decoy in case it hits the real output
for (uint64_t i: selected_indicies)
{
req.amounts.push_back(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution());
COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& rdisttib = req.amounts.back();
auto it = m_transfers.begin() + i;
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(it->m_ptx_wallet_info->m_tx.vout.size() > it->m_internal_output_index,
"m_internal_output_index = " << it->m_internal_output_index <<
" is greater or equal to outputs count = " << it->m_ptx_wallet_info->m_tx.vout.size());
req.amounts.push_back(it->is_zc() ? 0 : it->m_amount);
}
bool r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS(req, daemon_resp);
THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs.bin");
THROW_IF_FALSE_WALLET_EX(daemon_resp.status != API_RETURN_CODE_BUSY, error::daemon_busy, "getrandom_outs.bin");
THROW_IF_FALSE_WALLET_EX(daemon_resp.status == API_RETURN_CODE_OK, error::get_random_outs_error, daemon_resp.status);
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(daemon_resp.outs.size() == selected_indicies.size(),
"daemon returned wrong response for getrandom_outs.bin, wrong amounts count = " << daemon_resp.outs.size() << ", expected: " << selected_indicies.size());
std::vector<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> scanty_outs;
for(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs : daemon_resp.outs)
{
if (amount_outs.outs.size() < req.decoys_count)
rdisttib.own_global_index = it->m_global_output_index;
//check if we have Zarcanum era output of pre-Zarcanum
if (it->is_zc())
{
scanty_outs.push_back(amount_outs);
if(this->is_auditable())
continue;
//Zarcanum era
rdisttib.amount = 0;
//generate distribution in Zarcanum hardfork
THROW_IF_FALSE_WALLET_INT_ERR_EX(zarcanum_decoy_set_generator.is_initialized(), "zarcanum_decoy_set_generator are not initialized");
rdisttib.offsets = zarcanum_decoy_set_generator.generate_distribution(m_core_runtime_config.hf4_minimum_mixins);
need_to_request = true;
}
else
{
//for prezarcanum era use flat distribution
rdisttib.amount = it->m_amount;
rdisttib.offsets.resize(fake_outputs_count, 0);
}
}
THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
if (need_to_request)
{
size_t attempt_count = 0;
while (true)
{
daemon_resp = COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response();
bool r = m_core_proxy->call_COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2(req, daemon_resp);
THROW_IF_FALSE_WALLET_EX(r, error::no_connection_to_daemon, "getrandom_outs2.bin");
if (daemon_resp.status == API_RETURN_CODE_FAIL)
{
if (attempt_count < 10)
{
attempt_count++;
continue;
}
else
{
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(daemon_resp.outs.size() == selected_indicies.size(),
"unable to exacute getrandom_outs.bin after 10 attempts with code API_RETURN_CODE_FAIL, there must be problems with mixins");
}
}
THROW_IF_FALSE_WALLET_EX(daemon_resp.status != API_RETURN_CODE_BUSY, error::daemon_busy, "getrandom_outs.bin");
THROW_IF_FALSE_WALLET_EX(daemon_resp.status == API_RETURN_CODE_OK, error::get_random_outs_error, daemon_resp.status);
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(daemon_resp.outs.size() == selected_indicies.size(),
"daemon returned wrong response for getrandom_outs.bin, wrong amounts count = " << daemon_resp.outs.size() << ", expected: " << selected_indicies.size());
break;
}
std::vector<COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount> scanty_outs;
THROW_IF_FALSE_WALLET_EX(daemon_resp.outs.size() == req.amounts.size(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
//for (COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs : daemon_resp.outs)
for(size_t i = 0; i != daemon_resp.outs.size(); i++)
{
if (daemon_resp.outs[i].outs.size() != req.amounts[i].offsets.size())
{
scanty_outs.push_back(daemon_resp.outs[i]);
}
}
THROW_IF_FALSE_WALLET_EX(scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count);
}
}
//lets prefetch m_global_output_index for selected_indicies
@ -5910,6 +5993,12 @@ bool wallet2::prepare_tx_sources(size_t fake_outputs_count, std::vector<currency
src.transfer_index = it - m_transfers.begin();
src.amount = td.amount();
src.asset_id = td.get_asset_id();
size_t fake_outputs_count = fake_outputs_count_;
//redefine for hardfork
if (td.is_zc() && !this->is_auditable())
fake_outputs_count = m_core_runtime_config.hf4_minimum_mixins;
//paste mixin transaction
if (daemon_resp.outs.size())
{
@ -6431,9 +6520,9 @@ bool wallet2::select_indices_for_transfer(assets_selection_context& needed_money
return res;
}
//----------------------------------------------------------------------------------------------------
uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_indexes, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count)
uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_indexes, free_amounts_cache_type& found_free_amounts, uint64_t needed_money, uint64_t fake_outputs_count_)
{
WLT_LOG_GREEN("Selecting indices for transfer of " << print_money_brief(needed_money) << " with " << fake_outputs_count << " fake outs, found_free_amounts.size()=" << found_free_amounts.size() << "...", LOG_LEVEL_0);
WLT_LOG_GREEN("Selecting indices for transfer of " << print_money_brief(needed_money) << " with " << fake_outputs_count_ << " fake outs, found_free_amounts.size()=" << found_free_amounts.size() << "...", LOG_LEVEL_0);
uint64_t found_money = 0;
//uint64_t found_zc_input = false;
std::string selected_amounts_str;
@ -6445,6 +6534,11 @@ uint64_t wallet2::select_indices_for_transfer(std::vector<uint64_t>& selected_in
it = --found_free_amounts.end();
WLT_CHECK_AND_ASSERT_MES(it->second.size(), 0, "internal error: empty found_free_amounts map");
}
uint64_t fake_outputs_count = fake_outputs_count_;
if (!this->is_auditable() && m_transfers[*it->second.begin()].is_zc())
{
fake_outputs_count = m_core_runtime_config.hf4_minimum_mixins;
}
if (is_transfer_ready_to_go(m_transfers[*it->second.begin()], fake_outputs_count))
{
found_money += it->first;
@ -6481,7 +6575,7 @@ bool wallet2::is_transfer_able_to_go(const transfer_details& td, uint64_t fake_o
uint8_t mix_attr = CURRENCY_TO_KEY_OUT_RELAXED;
if (get_mix_attr_from_tx_out_v(out_v, mix_attr))
{
if (!currency::is_mixattr_applicable_for_fake_outs_counter(mix_attr, fake_outputs_count))
if (!currency::is_mixattr_applicable_for_fake_outs_counter(td.m_ptx_wallet_info->m_tx.version, mix_attr, fake_outputs_count, m_core_runtime_config))
return false;
}
@ -6507,7 +6601,13 @@ bool wallet2::prepare_free_transfers_cache(uint64_t fake_outputs_count)
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
if (is_transfer_able_to_go(td, fake_outputs_count))
uint64_t fake_outputs_count_local = fake_outputs_count;
if (td.m_zc_info_ptr)
{
//zarcanum out, redefine fake_outputs_count
fake_outputs_count_local = this->is_auditable() ? 0 : CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE;
}
if (is_transfer_able_to_go(td, fake_outputs_count_local))
{
//@#@
m_found_free_amounts[td.get_asset_id()][td.amount()].insert(i);
@ -6903,7 +7003,7 @@ bool wallet2::prepare_transaction(construct_tx_param& ctp, currency::finalize_tx
return true;
}
//----------------------------------------------------------------------------------------------------
void wallet2::finalize_transaction(const currency::finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key /* = true */)
void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key /* = true */)
{
currency::finalized_tx result = AUTO_VAL_INIT(result);
result.tx = tx;
@ -6913,7 +7013,7 @@ void wallet2::finalize_transaction(const currency::finalize_tx_param& ftp, curre
tx_key = result.one_time_key;
}
//----------------------------------------------------------------------------------------------------
void wallet2::finalize_transaction(const currency::finalize_tx_param& ftp, currency::finalized_tx& result, bool broadcast_tx, bool store_tx_secret_key /* = true */)
void wallet2::finalize_transaction(currency::finalize_tx_param& ftp, currency::finalized_tx& result, bool broadcast_tx, bool store_tx_secret_key /* = true */)
{
// NOTE: if broadcast_tx == true callback rise_on_transfer2() may be called at the end of this function.
// That callback may call balance(), so it's important to have all used/spending transfers
@ -6922,7 +7022,10 @@ void wallet2::finalize_transaction(const currency::finalize_tx_param& ftp, curre
// broadcasting tx without secret key storing is forbidden to avoid lost key issues
WLT_THROW_IF_FALSE_WALLET_INT_ERR_EX(!broadcast_tx || store_tx_secret_key, "finalize_tx is requested to broadcast a tx without storing the key");
//TIME_MEASURE_START_MS(construct_tx_time);
//overide mixins count for hardfork 4 outputs
if (is_in_hardfork_zone(ZANO_HARDFORK_04_ZARCANUM))
ftp.tx_outs_attr = m_core_runtime_config.hf4_minimum_mixins;
bool r = currency::construct_tx(m_account.get_keys(),
ftp, result);
//TIME_MEASURE_FINISH_MS(construct_tx_time);

View file

@ -47,7 +47,7 @@
#include "view_iface.h"
#include "wallet2_base.h"
#define WALLET_DEFAULT_TX_SPENDABLE_AGE 10
#define WALLET_DEFAULT_TX_SPENDABLE_AGE CURRENCY_HF4_MANDATORY_MIN_COINAGE
#define WALLET_POS_MINT_CHECK_HEIGHT_INTERVAL 1
@ -153,6 +153,7 @@ namespace tools
uint64_t m_height_of_start_sync = 0;
std::atomic<uint64_t> m_last_sync_percent = 0;
mutable uint64_t m_current_wallet_file_size = 0;
bool m_use_assets_whitelisting = true;
//===============================================================
@ -216,6 +217,7 @@ namespace tools
a & m_custom_assets;
a & m_rollback_events;
a & m_whitelisted_assets;
a & m_use_assets_whitelisting;
}
};
@ -633,8 +635,8 @@ namespace tools
bool prepare_transaction(construct_tx_param& ctp, currency::finalize_tx_param& ftp, const mode_separate_context& emode_separate = mode_separate_context());
void finalize_transaction(const currency::finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key = true);
void finalize_transaction(const currency::finalize_tx_param& ftp, currency::finalized_tx& result, bool broadcast_tx, bool store_tx_secret_key = true );
void finalize_transaction(currency::finalize_tx_param& ftp, currency::transaction& tx, crypto::secret_key& tx_key, bool broadcast_tx, bool store_tx_secret_key = true);
void finalize_transaction(currency::finalize_tx_param& ftp, currency::finalized_tx& result, bool broadcast_tx, bool store_tx_secret_key = true );
std::string get_log_prefix() const { return m_log_prefix; }
static uint64_t get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const wallet_public::employed_tx_entries& td);
@ -646,6 +648,7 @@ namespace tools
construct_tx_param get_default_construct_tx_param_inital();
void set_disable_tor_relay(bool disable);
uint64_t get_default_fee() {return TX_DEFAULT_FEE;}
uint64_t get_current_minimum_network_fee() { return TX_DEFAULT_FEE; }
void export_transaction_history(std::ostream& ss, const std::string& format, bool include_pos_transactions = true);
bool add_custom_asset_id(const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_descriptor);
@ -890,7 +893,6 @@ private:
bool m_use_deffered_global_outputs;
bool m_disable_tor_relay;
bool m_use_assets_whitelisting = true;
mutable current_operation_context m_current_context;
std::string m_votes_config_path;

View file

@ -731,7 +731,7 @@ if (!(cond))
{ \
exception_handler(); \
std::stringstream ss; \
ss << std::endl << mess; \
ss << std::endl << "[" << error_code << "]" << mess ; \
LOG_ERROR(#cond << ". THROW EXCEPTION: " << error_code << ss.str()); \
tools::error::throw_wallet_ex<tools::error::wallet_error>(std::string(__FILE__ ":" STRINGIZE(__LINE__)), ss.str(), error_code); \
}

View file

@ -274,6 +274,21 @@ namespace wallet_public
};
struct wallet_transfer_info_old : public wallet_transfer_info
{
uint64_t amount = 0;
bool is_income = false;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(is_income)
KV_SERIALIZE(amount)
KV_CHAIN_BASE(wallet_transfer_info)
END_KV_SERIALIZE_MAP()
};
struct asset_balance_entry_base
{
uint64_t total = 0;
@ -486,25 +501,25 @@ namespace wallet_public
#define ORDER_FROM_BEGIN_TO_END "FROM_BEGIN_TO_END"
#define ORDER_FROM_FROM_END_TO_BEGIN "FROM_END_TO_BEGIN"
struct COMMAND_RPC_GET_RECENT_TXS_AND_INFO
struct COMMAND_RPC_GET_RECENT_TXS_AND_INFO2
{
struct request
{
/*
if offset is 0, then GET_RECENT_TXS_AND_INFO return
unconfirmed transactions as the first first items of "transfers",
if offset is 0, then GET_RECENT_TXS_AND_INFO return
unconfirmed transactions as the first first items of "transfers",
this unconfirmed transactions is not counted regarding "count" parameter
*/
uint64_t offset;
uint64_t count;
/*
need_to_get_info - should backend re-calculate balance(could be relatively heavy,
and not needed when getting long tx history with multiple calls
/*
need_to_get_info - should backend re-calculate balance(could be relatively heavy,
and not needed when getting long tx history with multiple calls
of GET_RECENT_TXS_AND_INFO with offsets)
*/
bool update_provision_info;
bool update_provision_info;
bool exclude_mining_txs;
bool exclude_unconfirmed;
std::string order; // "FROM_BEGIN_TO_END" or "FROM_END_TO_BEGIN"
@ -535,6 +550,30 @@ namespace wallet_public
};
};
struct COMMAND_RPC_GET_RECENT_TXS_AND_INFO
{
typedef COMMAND_RPC_GET_RECENT_TXS_AND_INFO2::request request;
struct response
{
wallet_provision_info pi;
std::vector<wallet_transfer_info_old> transfers;
uint64_t total_transfers;
uint64_t last_item_index;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(pi)
KV_SERIALIZE(transfers)
KV_SERIALIZE(total_transfers)
KV_SERIALIZE(last_item_index)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_REGISTER_ALIAS
{
struct request
@ -561,9 +600,9 @@ namespace wallet_public
struct transfer_destination
{
uint64_t amount;
uint64_t amount = 0;
std::string address;
crypto::public_key asset_id;
crypto::public_key asset_id = currency::native_coin_asset_id;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE(address)

View file

@ -240,6 +240,7 @@ namespace tools
WALLET_RPC_CATCH_TRY_ENTRY();
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getwallet_info(const wallet_public::COMMAND_RPC_GET_WALLET_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
@ -258,6 +259,7 @@ namespace tools
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getwallet_restore_info(const wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
@ -265,6 +267,7 @@ namespace tools
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_seed_phrase_info(const wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::request& req, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
@ -272,7 +275,36 @@ namespace tools
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
//this is legacy api, should be removed after successful transition to HF4
wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO2::response rsp2 = AUTO_VAL_INIT(rsp2);
WALLET_RPC_BEGIN_TRY_ENTRY();
on_get_recent_txs_and_info2(req, rsp2, er, cntx);
res.pi = rsp2.pi;
res.total_transfers = rsp2.total_transfers;
res.last_item_index = rsp2.last_item_index;
for (const auto& item : rsp2.transfers)
{
res.transfers.push_back(wallet_public::wallet_transfer_info_old());
*static_cast<wallet_public::wallet_transfer_info*>(&res.transfers.back()) = item;
for (const auto& subitem : item.subtransfers)
{
if (subitem.asset_id == currency::native_coin_asset_id)
{
res.transfers.back().amount = subitem.amount;
res.transfers.back().is_income = subitem.is_income;
}
}
}
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_get_recent_txs_and_info2(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO2::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO2::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
WALLET_RPC_BEGIN_TRY_ENTRY();
if (req.update_provision_info)
@ -1021,7 +1053,7 @@ namespace tools
{
WALLET_RPC_BEGIN_TRY_ENTRY();
std::string buff = epee::string_encoding::base64_decode(req.buff);
bool r = w.get_wallet()->encrypt_buffer(buff, res.res_buff);
w.get_wallet()->encrypt_buffer(buff, res.res_buff);
res.res_buff = epee::string_encoding::base64_encode(res.res_buff);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();
@ -1031,7 +1063,7 @@ namespace tools
{
WALLET_RPC_BEGIN_TRY_ENTRY();
std::string buff = epee::string_encoding::base64_decode(req.buff);
bool r = w.get_wallet()->encrypt_buffer(buff, res.res_buff);
w.get_wallet()->encrypt_buffer(buff, res.res_buff);
res.res_buff = epee::string_encoding::base64_encode(res.res_buff);
return true;
WALLET_RPC_CATCH_TRY_ENTRY();

View file

@ -94,7 +94,8 @@ namespace tools
MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_public::COMMAND_RPC_GET_BALANCE)
MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_public::COMMAND_RPC_GET_ADDRESS)
MAP_JON_RPC_WE("get_wallet_info", on_getwallet_info, wallet_public::COMMAND_RPC_GET_WALLET_INFO)
MAP_JON_RPC_WE("get_recent_txs_and_info", on_get_recent_txs_and_info, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO)
MAP_JON_RPC_WE("get_recent_txs_and_info", on_get_recent_txs_and_info, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO) //LEGACY
MAP_JON_RPC_WE("get_recent_txs_and_info2", on_get_recent_txs_and_info2, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO2)
MAP_JON_RPC_WE("transfer", on_transfer, wallet_public::COMMAND_RPC_TRANSFER)
MAP_JON_RPC_WE("store", on_store, wallet_public::COMMAND_RPC_STORE)
MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_public::COMMAND_RPC_GET_PAYMENTS)
@ -150,6 +151,7 @@ namespace tools
bool on_getwallet_restore_info(const wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_RESTORE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_seed_phrase_info(const wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::request& req, wallet_public::COMMAND_RPC_GET_SEED_PHRASE_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_recent_txs_and_info2(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO2::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO2::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_store(const wallet_public::COMMAND_RPC_STORE::request& req, wallet_public::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx);
bool on_get_payments(const wallet_public::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_public::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx);

View file

@ -548,7 +548,10 @@ bool wallets_manager::init_local_daemon()
//chain calls to rpc server
m_prpc_chain_handler = &m_wallet_rpc_server;
//disable this for main net until we get full support of authentication with network
#ifdef TESTNET
m_rpc_server.set_rpc_chain_handler(this);
#endif
LOG_PRINT_L0("Starting core rpc server...");
@ -1805,6 +1808,12 @@ std::string wallets_manager::reset_wallet_password(uint64_t wallet_id, const std
else
return API_RETURN_CODE_FAIL;
}
std::string wallets_manager::use_whitelisting(uint64_t wallet_id, bool use)
{
GET_WALLET_OPT_BY_ID(wallet_id, w);
w.w->get()->set_use_assets_whitelisting(use);
return API_RETURN_CODE_OK;
}
std::string wallets_manager::add_custom_asset_id(uint64_t wallet_id, const crypto::public_key& asset_id, currency::asset_descriptor_base& asset_descriptor)
{
GET_WALLET_OPT_BY_ID(wallet_id, w);

View file

@ -137,6 +137,7 @@ public:
std::string get_wallet_restore_info(uint64_t wallet_id, std::string& seed_phrase, const std::string& seed_password);
std::string backup_wallet(uint64_t wallet_id, const std::wstring& path);
std::string reset_wallet_password(uint64_t wallet_id, const std::string& pass);
std::string use_whitelisting(uint64_t wallet_id, bool use);
std::string is_wallet_password_valid(uint64_t wallet_id, const std::string& pass);
std::string create_ionic_swap_proposal(uint64_t wallet_id, const tools::wallet_public::create_ionic_swap_proposal_request& proposal, std::string& result_proposal_hex);
std::string get_ionic_swap_proposal_info(uint64_t wallet_id, std::string&raw_tx_template_hex, tools::wallet_public::ionic_swap_proposal_info& proposal);

View file

@ -1068,7 +1068,7 @@ bool gen_alias_too_small_reward::generate(std::vector<test_event_entry>& events)
set_hard_fork_heights_to_generator(generator);
DO_CALLBACK(events, "configure_core");
DO_CALLBACK(events, "init_runtime_config");
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW+20);
transaction tx_1 = AUTO_VAL_INIT(tx_1);
r = construct_tx_with_many_outputs(m_hardforks, events, blk_0r, miner_acc.get_keys(), miner_acc.get_public_address(), 3 * aliases_count * TESTS_DEFAULT_FEE * 100, 3 * aliases_count, TESTS_DEFAULT_FEE, tx_1);
@ -1271,7 +1271,8 @@ bool gen_alias_switch_and_check_block_template::generate(std::vector<test_event_
uint64_t miner_amount = get_outs_money_amount(blk_0r.miner_tx, miner_acc.get_keys()) * 4;
// alice get some money
MAKE_TX_LIST(events, tx_list, miner_acc, alice, miner_amount / 2, blk_0r); // 2N+3
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, tx_list); // 2N+4
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1_, blk_0r, miner_acc, tx_list); // 2N+4
REWIND_BLOCKS_N_WITH_TIME(events, blk_1, blk_1_, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1); // 2N = CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2
tx_list.clear();
// Alice registers an alias

View file

@ -300,6 +300,7 @@ bool test_generator::construct_block(currency::block& blk,
size_t target_block_size = txs_size + 0; // zero means no cost for ordinary coinbase
tx_generation_context miner_tx_tgc{};
uint64_t block_reward_without_fee = 0;
uint64_t block_reward = 0;
while (true)
{
r = construct_miner_tx(height, misc_utils::median(block_sizes),
@ -310,6 +311,7 @@ bool test_generator::construct_block(currency::block& blk,
miner_acc.get_keys().account_address,
blk.miner_tx,
block_reward_without_fee,
block_reward,
get_tx_version(height, m_hardforks),
blobdata(),
test_generator::get_test_gentime_settings().miner_tx_max_outs,
@ -356,7 +358,7 @@ bool test_generator::construct_block(currency::block& blk,
else
{
//need to build pos block
r = sign_block(wallets[won_walled_index].mining_context, pe, block_reward_without_fee + total_fee, *wallets[won_walled_index].wallet, miner_tx_tgc, blk);
r = sign_block(wallets[won_walled_index].mining_context, pe, block_reward, *wallets[won_walled_index].wallet, miner_tx_tgc, blk);
CHECK_AND_ASSERT_MES(r, false, "Failed to find_kernel_and_sign()");
}
@ -448,6 +450,16 @@ bool test_generator::build_wallets(const blockchain_vector& blockchain,
{
for (uint64_t amount : rqt.amounts)
{
uint64_t height_upper_limit_local = rqt.height_upper_limit;
if (amount == 0)
{
//for hardfork 4 we need to have at least 10 confirmations on hard rule level
//rqt.height_upper_limit > - 10
if (m_blockchain.size() < CURRENCY_HF4_MANDATORY_MIN_COINAGE)
return false;
if (height_upper_limit_local > m_blockchain.size() - CURRENCY_HF4_MANDATORY_MIN_COINAGE)
height_upper_limit_local = m_blockchain.size() - CURRENCY_HF4_MANDATORY_MIN_COINAGE;
}
rsp.outs.resize(rsp.outs.size() + 1);
auto& rsp_entry = rsp.outs.back();
rsp_entry.amount = amount;
@ -463,7 +475,7 @@ bool test_generator::build_wallets(const blockchain_vector& blockchain,
for (size_t gindex : random_mapping)
{
const out_index_info& oii = it->second[gindex];
if (rqt.height_upper_limit != 0 && oii.block_height > rqt.height_upper_limit)
if (height_upper_limit_local != 0 && oii.block_height > height_upper_limit_local)
continue;
const transaction& tx = oii.in_block_tx_index == 0 ? m_blockchain[oii.block_height]->b.miner_tx : m_blockchain[oii.block_height]->m_transactions[oii.in_block_tx_index - 1];
auto& out_v = tx.vout[oii.in_tx_out_index];
@ -941,9 +953,11 @@ bool test_generator::construct_block(int64_t manual_timestamp_adjustment,
else
{
uint64_t base_block_reward = 0;
uint64_t block_reward = 0;
size_t current_block_size = txs_sizes + get_object_blobsize(blk.miner_tx);
// TODO: This will work, until size of constructed block is less then CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE
if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0, miner_acc.get_public_address(), miner_acc.get_public_address(), blk.miner_tx, base_block_reward, get_tx_version(height, m_hardforks), blobdata(), 1))
if (!construct_miner_tx(height, misc_utils::median(block_sizes), already_generated_coins, current_block_size, 0,
miner_acc.get_public_address(), miner_acc.get_public_address(), blk.miner_tx, base_block_reward, block_reward, get_tx_version(height, m_hardforks), blobdata(), 1))
return false;
}
@ -1193,8 +1207,6 @@ namespace
bool init_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const std::vector<currency::block>& blockchain, const map_hash2tx_t& mtx, const currency::account_keys& acc_keys)
{
bool r = false;
for (const block& blk : blockchain)
{
uint64_t height = get_block_height(blk);
@ -1487,6 +1499,11 @@ bool fill_tx_sources(std::vector<currency::tx_source_entry>& sources, const std:
if (unlock_time > head_block_ts + DIFFICULTY_TOTAL_TARGET)
continue;
}
}
if (blk_head.miner_tx.version >= TRANSACTION_VERSION_POST_HF4 && next_block_height - get_block_height(*oi.p_blk) < CURRENCY_HF4_MANDATORY_MIN_COINAGE)
{
//ignore outs that doesn't fit the HF4 rule
continue;
}
@ -2338,7 +2355,6 @@ bool shuffle_source_entries(std::vector<tx_source_entry>& sources)
// creates destinations.size() + 1 outputs if the total sum of amounts is less than the original premine amount (the last one will have amount = old_premine - sum)
bool replace_coinbase_in_genesis_block(const std::vector<currency::tx_destination_entry>& destinations, test_generator& generator, std::vector<test_event_entry>& events, currency::block& genesis_block)
{
bool r = false;
generator.remove_block_info(genesis_block);
events.pop_back();
@ -2478,6 +2494,7 @@ bool test_chain_unit_enchanced::configure_core(currency::core& c, size_t ev_inde
currency::core_runtime_config pc = c.get_blockchain_storage().get_core_runtime_config();
pc.min_coinstake_age = TESTS_POS_CONFIG_MIN_COINSTAKE_AGE;
pc.pos_minimum_heigh = TESTS_POS_CONFIG_POS_MINIMUM_HEIGH;
pc.hf4_minimum_mixins = 0;
pc.hard_forks = m_hardforks;
c.get_blockchain_storage().set_core_runtime_config(pc);
return true;

View file

@ -585,6 +585,9 @@ public:
void set_hardforks(const currency::hard_forks_descriptor& hardforks);
const currency::hard_forks_descriptor& get_hardforks() const { return m_hardforks; }
void load_hardforks_from(const test_chain_unit_base* pthis) { m_hardforks = pthis->get_hardforks(); }
template<typename t_type>
void load_hardforks_from(const t_type* pthis) {}
private:
bool m_ignore_last_pow_in_wallets;
@ -954,10 +957,11 @@ bool test_generator::construct_block_gentime_with_coinbase_cb(const currency::bl
//size_t current_block_size = get_object_blobsize(miner_tx);
uint64_t block_reward_without_fee = 0;
uint64_t block_reward = 0;
currency::keypair tx_sec_key = currency::keypair::generate();
r = construct_miner_tx(height, epee::misc_utils::median(block_sizes), already_generated_coins, 0 /* current_block_size !HACK! */, 0,
acc.get_public_address(), acc.get_public_address(), miner_tx, block_reward_without_fee, get_tx_version(height, m_hardforks), currency::blobdata(), /* max outs: */ 1,
acc.get_public_address(), acc.get_public_address(), miner_tx, block_reward_without_fee, block_reward, get_tx_version(height, m_hardforks), currency::blobdata(), /* max outs: */ 1,
/* pos: */ false, currency::pos_entry(), /* ogc_ptr: */ nullptr, &tx_sec_key);
CHECK_AND_ASSERT_MES(r, false, "construct_miner_tx failed");

View file

@ -197,7 +197,8 @@ bool generate_and_play(const char* const genclass_name, size_t hardfork_id = SIZ
std::vector<test_event_entry> events;
bool generated = false;
bool result = false;
std::cout << ENDL << concolor::bright_white << "#TEST# >>>> " << genclass_name << " <<<<" << ENDL << ENDL;
//std::cout << ENDL << concolor::bright_white << "#TEST# >>>> " << genclass_name << " <<<<" << ENDL << ENDL;
LOG_PRINT_MAGENTA( "#TEST# >>>> " << genclass_name << " <<<<" << ENDL, LOG_LEVEL_0);
LOG_PRINT2("get_object_blobsize.log", "#TEST# " << genclass_name, LOG_LEVEL_3);
@ -231,16 +232,16 @@ bool generate_and_play(const char* const genclass_name, size_t hardfork_id = SIZ
generated = g.generate(events);
if (generated)
{
std::cout << concolor::normal << events.size() << " events generated successfully" << std::endl;
LOG_PRINT_MAGENTA( events.size() << " events generated successfully" << std::endl, LOG_LEVEL_0);
if (has_non_default_hardforks || g.get_hardforks() != tcub.get_hardforks())
{
size_t configure_core_events_count = std::count_if(events.begin(), events.end(), [](auto& ev){ return ev.type() == typeid(callback_entry) && boost::get<callback_entry>(ev).callback_name == "configure_core"; });
CHECK_AND_ASSERT_THROW_MES(configure_core_events_count != 0, "Test " << genclass_name << " has non-default hardfork settings and therefore must use 'configure_core' callback");
}
std::cout << concolor::bright_white << std::string(100, '=') << std::endl <<
LOG_PRINT_MAGENTA(std::string(100, '=') << std::endl <<
"#TEST# >>>> " << genclass_name << " <<<< start replaying events" << std::endl <<
std::string(100, '=') << concolor::normal << std::endl;
std::string(100, '=') << std::endl, LOG_LEVEL_0);
result = do_replay_events(events, g);
}
@ -263,18 +264,18 @@ bool generate_and_play(const char* const genclass_name, size_t hardfork_id = SIZ
if (result)
{
std::cout << concolor::green << std::string(100, '=') << std::endl <<
LOG_PRINT_GREEN(std::string(100, '=') << std::endl <<
"#TEST# >>>> " << genclass_name << " <<<< Succeeded" << std::endl <<
std::string(100, '=') << concolor::normal << std::endl;
std::string(100, '=') << std::endl, LOG_LEVEL_0 );
}
else
{
std::cout << concolor::red << std::string(100, '=') << std::endl <<
LOG_PRINT_RED( std::string(100, '=') << std::endl <<
"#TEST# >>>> " << genclass_name << " <<<< FAILED" << std::endl <<
std::string(100, '=') << concolor::normal << std::endl;
std::string(100, '=') << std::endl, LOG_LEVEL_0);
result = false;
}
std::cout << std::endl;
//std::cout << std::endl;
return result;
}
@ -1078,7 +1079,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(wallet_outputs_with_same_key_image);
GENERATE_AND_PLAY(wallet_unconfirmed_tx_expiration);
GENERATE_AND_PLAY(wallet_unconfimed_tx_balance);
GENERATE_AND_PLAY_HF(packing_outputs_on_pos_minting_wallet, "3-*");
GENERATE_AND_PLAY_HF(packing_outputs_on_pos_minting_wallet, "3");
GENERATE_AND_PLAY(wallet_watch_only_and_chain_switch);
GENERATE_AND_PLAY(wallet_rpc_integrated_address);
@ -1231,7 +1232,7 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(hard_fork_2_tx_payer_in_wallet);
GENERATE_AND_PLAY(hard_fork_2_tx_receiver_in_wallet);
GENERATE_AND_PLAY(hard_fork_2_tx_extra_alias_entry_in_wallet);
GENERATE_AND_PLAY(hard_fork_2_auditable_addresses_basics);
GENERATE_AND_PLAY_HF(hard_fork_2_auditable_addresses_basics, "2-*");
GENERATE_AND_PLAY(hard_fork_2_no_new_structures_before_hf);
GENERATE_AND_PLAY(hard_fork_2_awo_wallets_basic_test<true>);
GENERATE_AND_PLAY(hard_fork_2_awo_wallets_basic_test<false>);
@ -1240,13 +1241,16 @@ int main(int argc, char* argv[])
GENERATE_AND_PLAY(hard_fork_2_incorrect_alias_update<true>);
GENERATE_AND_PLAY(hard_fork_2_incorrect_alias_update<false>);
// HF4
// GENERATE_AND_PLAY_HF(hard_fork_4_consolidated_txs, "4"); TODO, doesn't work atm -- sowle
// atomics
GENERATE_AND_PLAY(atomic_simple_test);
GENERATE_AND_PLAY(atomic_test_wrong_redeem_wrong_refund);
GENERATE_AND_PLAY(atomic_test_altchain_simple);
GENERATE_AND_PLAY(atomic_test_check_hardfork_rules);
GENERATE_AND_PLAY(isolate_auditable_and_proof);
GENERATE_AND_PLAY_HF(isolate_auditable_and_proof, "2-*");
GENERATE_AND_PLAY(zarcanum_basic_test);

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -38,9 +38,10 @@
#include "hard_fork_1_bad_pos_source.h"
#include "hard_fork_1.h"
#include "hard_fork_2.h"
#include "hard_fork_4.h"
#include "atomic_tests.h"
#include "isolate_auditable_and_proof.h"
#include "zarcanum_test.h"
#include "multiassets_test.h"
#include "ionic_swap_tests.h"
#include "attachment_isolation_encryption_test.h"
#include "attachment_isolation_encryption_test.h"

View file

@ -681,6 +681,7 @@ gen_no_attchments_in_coinbase::gen_no_attchments_in_coinbase()
bool gen_no_attchments_in_coinbase::generate(std::vector<test_event_entry>& events) const
{
this->on_test_generator_created(generator);
uint64_t ts = 1450000000;
test_core_time::adjust(ts);
@ -704,7 +705,16 @@ bool gen_no_attchments_in_coinbase::init_config_set_cp(currency::core& c, size_t
crc.pos_minimum_heigh = 1;
c.get_blockchain_storage().set_core_runtime_config(crc);
m_checkpoints.add_checkpoint(12, "475331fb4a325e722ddbc2d087d32687a58392e5a9314001120de0f2ce7737f2");
// different checkpoints due to different block versions for different hardforks -> different hashes
if (crc.is_hardfork_active_for_height(ZANO_HARDFORK_03, 11) && !crc.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, 11))
{
m_checkpoints.add_checkpoint(12, "4e6055dda442e04b2feb70bc7245584742604e8515b8d2e1c3d46c26f758d59f");
}
else
{
m_checkpoints.add_checkpoint(12, "475331fb4a325e722ddbc2d087d32687a58392e5a9314001120de0f2ce7737f2");
}
c.set_checkpoints(currency::checkpoints(m_checkpoints));
return true;

View file

@ -612,7 +612,6 @@ bool hard_fork_2_tx_extra_alias_entry_in_wallet::c1(currency::core& c, size_t ev
//------------------------------------------------------------------------------
hard_fork_2_auditable_addresses_basics::hard_fork_2_auditable_addresses_basics()
: hard_fork_2_base_test(23)
{
REGISTER_CALLBACK_METHOD(hard_fork_2_auditable_addresses_basics, c1);
}
@ -644,6 +643,8 @@ bool hard_fork_2_auditable_addresses_basics::generate(std::vector<test_event_ent
// make sure all Bob's outputs has mix_attr = 1
for (auto& out : tx_1.vout)
{
if (out.type() != typeid(tx_out_bare))
continue; // skip if we're in postzarcanum era
if (boost::get<tx_out_bare>(out).amount != MK_TEST_COINS(5))
continue; // skip change
uint8_t mix_attr = boost::get<txout_to_key>(boost::get<tx_out_bare>(out).target).mix_attr;
@ -677,6 +678,9 @@ bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_ind
// make sure all Bob's outputs has mix_attr = 1
for (auto& out : tx.vout)
{
if (out.type() != typeid(tx_out_bare))
continue; // skip if we're in postzarcanum era
if (boost::get<tx_out_bare>(out).amount != MK_TEST_COINS(1))
continue; // skip change
uint8_t mix_attr = boost::get<txout_to_key>(boost::get<tx_out_bare>(out).target).mix_attr;
@ -702,6 +706,9 @@ bool hard_fork_2_auditable_addresses_basics::c1(currency::core& c, size_t ev_ind
// make sure all Bob's outputs has mix_attr = 1
for (auto& out : tx.vout)
{
if (out.type() != typeid(tx_out_bare))
continue; // skip if we're in postzarcanum era
if (boost::get<tx_out_bare>(out).amount != MK_TEST_COINS(1))
continue; // skip change
uint8_t mix_attr = boost::get<txout_to_key>(boost::get<tx_out_bare>(out).target).mix_attr;

View file

@ -41,7 +41,7 @@ struct hard_fork_2_tx_extra_alias_entry_in_wallet : public hard_fork_2_base_test
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
};
struct hard_fork_2_auditable_addresses_basics : public hard_fork_2_base_test
struct hard_fork_2_auditable_addresses_basics : public wallet_test //hard_fork_2_base_test
{
hard_fork_2_auditable_addresses_basics();
bool generate(std::vector<test_event_entry>& events) const;

View file

@ -0,0 +1,223 @@
// Copyright (c) 2023-2024 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "chaingen.h"
#include "hard_fork_4.h"
#include "random_helper.h"
using namespace currency;
namespace currency
{
bool construct_tx(const account_keys& sender_account_keys, const std::vector<tx_source_entry>& sources,
const std::vector<tx_destination_entry>& destinations,
const std::vector<extra_v>& extra,
const std::vector<attachment_v>& attachments,
transaction& tx,
uint64_t tx_version,
crypto::secret_key& one_time_secret_key,
uint64_t unlock_time,
uint64_t expiration_time,
uint8_t tx_outs_attr,
bool shuffle,
uint64_t flags,
uint64_t explicit_consolidated_tx_fee,
tx_generation_context& gen_context)
{
//extra copy operation, but creating transaction is not sensitive to this
finalize_tx_param ftp{};
ftp.tx_version = tx_version;
ftp.sources = sources;
ftp.prepared_destinations = destinations;
ftp.extra = extra;
ftp.attachments = attachments;
ftp.unlock_time = unlock_time;
// ftp.crypt_address = crypt_destination_addr;
ftp.expiration_time = expiration_time;
ftp.tx_outs_attr = tx_outs_attr;
ftp.shuffle = shuffle;
ftp.flags = flags;
ftp.mode_separate_fee = explicit_consolidated_tx_fee;
finalized_tx ft = AUTO_VAL_INIT(ft);
ft.tx = tx;
ft.one_time_key = one_time_secret_key;
ftp.gen_context = gen_context; // ftp, not ft here, this is UGLY -- sowle
bool r = construct_tx(sender_account_keys, ftp, ft);
tx = ft.tx;
one_time_secret_key = ft.one_time_key;
gen_context = ft.ftp.gen_context;
return r;
}
} // namespace currency
void add_flags_to_all_destination_entries(const uint64_t flags, std::vector<currency::tx_destination_entry>& destinations)
{
for(auto& de : destinations)
de.flags |= flags;
}
//-------------------------------
hard_fork_4_consolidated_txs::hard_fork_4_consolidated_txs()
{
REGISTER_CALLBACK_METHOD(hard_fork_4_consolidated_txs, c1);
}
bool hard_fork_4_consolidated_txs::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
account_base& bob_acc = m_accounts[BOB_ACC_IDX]; bob_acc.generate(); bob_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
DO_CALLBACK(events, "configure_core"); // necessary for the test to be run by GENERATE_AND_PLAY_HF
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
m_post_hf4_zarcanum = get_hardforks().get_the_most_recent_hardfork_id_for_height(CURRENCY_MINED_MONEY_UNLOCK_WINDOW) >= ZANO_HARDFORK_04_ZARCANUM;
uint64_t alice_amount = MK_TEST_COINS(50);
MAKE_TX(events, tx_0a, miner_acc, alice_acc, alice_amount, blk_0r);
// tx_0b is only needed for decoy outputs with amount = alice_amount (important only for pre-HF4)
transaction tx_0b{};
construct_tx_with_many_outputs(m_hardforks, events, blk_0r, miner_acc.get_keys(), miner_acc.get_public_address(), alice_amount * 10, 10, TESTS_DEFAULT_FEE, tx_0b);
ADD_CUSTOM_EVENT(events, tx_0b);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_1, blk_0r, miner_acc, std::list<transaction>({tx_0a, tx_0b}));
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// check Alice's balance
std::shared_ptr<tools::wallet2> alice_wlt;
r = generator.init_test_wallet(alice_acc, get_block_hash(blk_0), alice_wlt);
CHECK_AND_ASSERT_MES(r, false, "init_test_wallet failed");
r = generator.refresh_test_wallet(events, alice_wlt.get(), get_block_hash(blk_1r), 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
CHECK_AND_ASSERT_MES(r, false, "refresh_test_wallet failed");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice", alice_amount, 0, alice_amount, 0, 0), false, "");
uint64_t miner_amount = MK_TEST_COINS(60);
uint64_t bob_amount = miner_amount + alice_amount - TX_DEFAULT_FEE;
// Consolidated tx (TX_FLAG_SIGNATURE_MODE_SEPARATE).
// this data will be transferred between stage 1 and 2
transaction tx_1{};
crypto::secret_key one_time_secret_key{};
tx_generation_context gen_context{};
// Part 1/2, miner's inputs
{
std::vector<tx_source_entry> sources;
r = fill_tx_sources(sources, events, blk_1r, miner_acc.get_keys(), miner_amount, 10);
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
uint64_t miner_change = get_sources_total_amount(sources) - miner_amount;
std::vector<tx_destination_entry> destinations;
if (miner_change != 0)
destinations.push_back(tx_destination_entry(miner_change, miner_acc.get_public_address()));
destinations.push_back(tx_destination_entry(bob_amount, bob_acc.get_public_address()));
add_flags_to_all_destination_entries(tx_destination_entry_flags::tdef_explicit_native_asset_id, destinations);
r = construct_tx(miner_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_1, get_tx_version_from_events(events), one_time_secret_key,
0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, TX_DEFAULT_FEE, gen_context);
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
// partially completed tx_1 shouldn't be accepted
//DO_CALLBACK(events, "mark_invalid_tx");
ADD_CUSTOM_EVENT(events, tx_1);
MAKE_NEXT_BLOCK_TX1(events, blk_2a, blk_1r, miner_acc, tx_1);
}
// Part 2/2, Alice's inputs
{
std::vector<tx_source_entry> sources;
r = fill_tx_sources(sources, events, blk_1r, alice_acc.get_keys(), alice_amount, 10);
CHECK_AND_ASSERT_MES(r, false, "fill_tx_sources failed");
CHECK_AND_ASSERT_MES(get_sources_total_amount(sources) == alice_amount, false, "no change for Alice is expected");
sources.back().separately_signed_tx_complete = true;
std::vector<tx_destination_entry> destinations;
r = construct_tx(alice_acc.get_keys(), sources, destinations, empty_extra, empty_attachment, tx_1, get_tx_version_from_events(events), one_time_secret_key,
0, 0, 0, true, TX_FLAG_SIGNATURE_MODE_SEPARATE, 0 /* note zero fee here */, gen_context);
CHECK_AND_ASSERT_MES(r, false, "construct_tx failed");
ADD_CUSTOM_EVENT(events, tx_1);
}
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_1);
//std::shared_ptr<tools::wallet2> bob_wlt;
//r = generator.init_test_wallet(bob_acc, get_block_hash(blk_0), bob_wlt);
//CHECK_AND_ASSERT_MES(r, false, "init_test_wallet failed");
//r = generator.refresh_test_wallet(events, bob_wlt.get(), get_block_hash(blk_2), 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2);
//CHECK_AND_ASSERT_MES(r, false, "refresh_test_wallet failed");
//CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", bob_amount, 0, 0, 0, 0), false, "");
return true;
}
bool hard_fork_4_consolidated_txs::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
return true;
}
/*
hardfork_4_explicit_native_ids_in_outs::hardfork_4_explicit_native_ids_in_outs()
{
REGISTER_CALLBACK_METHOD(hardfork_4_explicit_native_ids_in_outs, c1);
m_hardforks.clear();
m_hardforks.set_hardfork_height(ZANO_HARDFORK_04_ZARCANUM, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1);
}
bool hardfork_4_explicit_native_ids_in_outs::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
account_base& alice_acc = m_accounts[ALICE_ACC_IDX]; alice_acc.generate(); alice_acc.set_createtime(ts);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, ts);
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
REWIND_BLOCKS_N_WITH_TIME(events, blk_0r, blk_0, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
DO_CALLBACK_PARAMS(events, "check_hardfork_inactive", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
// tx_0: miner -> Alice
// make tx_0 before HF4, so Alice will have only bare outs
m_alice_initial_balance = MK_TEST_COINS(1000);
MAKE_TX(events, tx_0, miner_acc, alice_acc, m_alice_initial_balance, blk_0r);
MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_acc, tx_0);
// make sure HF4 has been activated
DO_CALLBACK_PARAMS(events, "check_hardfork_active", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
// rewind blocks
REWIND_BLOCKS_N_WITH_TIME(events, blk_1r, blk_1, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// check Alice's balance and make sure she cannot deploy an asset
DO_CALLBACK(events, "c1_alice_cannot_deploy_asset");
// tx_1: Alice -> Alice (all coins) : this will convert all Alice outputs to ZC outs
MAKE_TX(events, tx_1, alice_acc, alice_acc, m_alice_initial_balance - TESTS_DEFAULT_FEE, blk_1r);
return true;
}
bool hardfork_4_explicit_native_ids_in_outs::c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events)
{
return true;
}
*/

View file

@ -0,0 +1,26 @@
// Copyright (c) 2023-2024 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include "chaingen.h"
#include "wallet_tests_basic.h"
struct hard_fork_4_consolidated_txs : public wallet_test
{
hard_fork_4_consolidated_txs();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
mutable bool m_post_hf4_zarcanum = false;
};
struct hardfork_4_explicit_native_ids_in_outs : public wallet_test
{
hardfork_4_explicit_native_ids_in_outs();
bool generate(std::vector<test_event_entry>& events) const;
bool c1(currency::core& c, size_t ev_index, const std::vector<test_event_entry>& events);
mutable uint64_t m_alice_initial_balance = 0;
};

View file

@ -178,7 +178,7 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
// Alice wants to trade with Bob, to exchange 10.0 TCT to 0.5 ZANO
view::ionic_swap_proposal_info proposal_details = AUTO_VAL_INIT(proposal_details);
proposal_details.fee_paid_by_a = TESTS_DEFAULT_FEE;
proposal_details.mixins = 10;
proposal_details.mixins = c.get_blockchain_storage().get_core_runtime_config().hf4_minimum_mixins;
proposal_details.to_finalizer.push_back(view::asset_funds{ asset_id , assets_to_exchange });
proposal_details.to_initiator.push_back(view::asset_funds{ currency::native_coin_asset_id , native_coins_to_exchange });
@ -233,7 +233,7 @@ bool ionic_swap_basic_test::c1(currency::core& c, size_t ev_index, const std::ve
//now Alice want to trade with Bob, to send 0.5 ZANO and get 10.0 TCT in exchange
view::ionic_swap_proposal_info proposal_details = AUTO_VAL_INIT(proposal_details);
proposal_details.fee_paid_by_a = TESTS_DEFAULT_FEE;
proposal_details.mixins = 10;
proposal_details.mixins = c.get_blockchain_storage().get_core_runtime_config().hf4_minimum_mixins;
proposal_details.to_finalizer.push_back(view::asset_funds{ currency::native_coin_asset_id , native_coins_to_exchange });
proposal_details.to_initiator.push_back(view::asset_funds{ asset_id , assets_to_exchange });
@ -375,7 +375,7 @@ bool ionic_swap_exact_amounts_test::c1(currency::core& c, size_t ev_index, const
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", adb.total_max_supply, 0, adb.total_max_supply, 0, 0, asset_id), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*carol_wlt, "Carol", MK_TEST_COINS(21), 0, MK_TEST_COINS(21), 0, 0), false, "");
size_t current_blockchain_size = c.get_current_blockchain_size();
//size_t current_blockchain_size = c.get_current_blockchain_size();
// Normal ionic swap between Alice and Bob: (Alice has only coins with explicit asset id)
// before:
@ -387,7 +387,7 @@ bool ionic_swap_exact_amounts_test::c1(currency::core& c, size_t ev_index, const
proposal_details.to_initiator.push_back(view::asset_funds{ asset_id, adb.total_max_supply });
proposal_details.to_finalizer.push_back(view::asset_funds{ native_coin_asset_id, MK_TEST_COINS(20) });
proposal_details.fee_paid_by_a = MK_TEST_COINS(1);
proposal_details.mixins = 2;
proposal_details.mixins = c.get_blockchain_storage().get_core_runtime_config().hf4_minimum_mixins;
tools::wallet_public::ionic_swap_proposal proposal{};
alice_wlt->create_ionic_swap_proposal(proposal_details, m_accounts[BOB_ACC_IDX].get_public_address(), proposal);
@ -399,7 +399,9 @@ bool ionic_swap_exact_amounts_test::c1(currency::core& c, size_t ev_index, const
proposal_decoded_info.to_initiator == proposal_details.to_initiator &&
proposal_decoded_info.fee_paid_by_a == proposal_details.fee_paid_by_a &&
proposal_decoded_info.mixins == proposal_details.mixins,
false, "actual and decoded proposal mismatch");
false, "actual and decoded proposal mismatch \nproposal_decoded_info: "
<< epee::serialization::store_t_to_json(proposal_decoded_info) <<
"\nproposal_details" << epee::serialization::store_t_to_json(proposal_details));
currency::transaction tx_is{};
r = bob_wlt->accept_ionic_swap_proposal(proposal, tx_is);
@ -427,7 +429,7 @@ bool ionic_swap_exact_amounts_test::c1(currency::core& c, size_t ev_index, const
proposal_details.to_initiator.push_back(view::asset_funds{ asset_id, adb.total_max_supply });
proposal_details.to_finalizer.push_back(view::asset_funds{ native_coin_asset_id, MK_TEST_COINS(20) });
proposal_details.fee_paid_by_a = MK_TEST_COINS(1);
proposal_details.mixins = 2;
proposal_details.mixins = c.get_blockchain_storage().get_core_runtime_config().hf4_minimum_mixins;
proposal = tools::wallet_public::ionic_swap_proposal{};
carol_wlt->create_ionic_swap_proposal(proposal_details, m_accounts[ALICE_ACC_IDX].get_public_address(), proposal);

View file

@ -44,7 +44,7 @@ bool isolate_auditable_and_proof::generate(std::vector<test_event_entry>& events
generator.construct_genesis_block(blk_0, genesis_acc, test_core_time::get_time());
events.push_back(blk_0);
DO_CALLBACK(events, "configure_core");
REWIND_BLOCKS_N(events, blk_0r, blk_0, m_mining_accunt, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5);
REWIND_BLOCKS_N(events, blk_0r, blk_0, m_mining_accunt, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 15);
DO_CALLBACK(events, "c1");
epee::debug::get_set_enable_assert(true, false);

View file

@ -154,7 +154,7 @@ bool multiassets_basic_test::c1(currency::core& c, size_t ev_index, const std::v
CHECK_AND_ASSERT_MES(it_asset != balances.end() && it_native != balances.end(), false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_asset->second.total == AMOUNT_ASSETS_TO_TRANSFER_MULTIASSETS_BASIC, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native->second.total == uint64_t(17517226)*COIN, false, "Failed to find needed asset in result balances");
CHECK_AND_ASSERT_MES(it_native->second.total == uint64_t(17517225990000000000), false, "Failed to find needed asset in result balances");
balances.clear();
@ -716,8 +716,6 @@ bool assets_and_pos_mining::generate(std::vector<test_event_entry>& events) cons
{
// Test idea: ensure that post-HF4 Zarcanum staking functions correctly with outputs that have a nonzero asset id blinding mask (i.e., outputs with a non-explicit asset id)
bool r = false;
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);

View file

@ -167,9 +167,10 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
// generate miner tx using incorrect current_block_size only for size estimation
uint64_t block_reward_without_fee = 0;
uint64_t block_reward = 0;
size_t estimated_block_size = m_txs_total_size;
bool r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee,
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
CHECK_AND_ASSERT_THROW_MES(r, "construct_miner_tx failed");
estimated_block_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx);
@ -177,7 +178,7 @@ void pos_block_builder::step4_generate_coinbase_tx(size_t median_size,
for (size_t try_count = 0; try_count != 10; ++try_count)
{
r = construct_miner_tx(m_height, median_size, already_generated_coins, estimated_block_size, m_total_fee,
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
reward_receiver_address, stakeholder_address, m_block.miner_tx, block_reward_without_fee, block_reward, tx_version, extra_nonce, max_outs, true, pe, &m_miner_tx_tgc, tx_one_time_key_to_use);
CHECK_AND_ASSERT_THROW_MES(r, "construct_homemade_pos_miner_tx failed");
cumulative_size = m_txs_total_size + get_object_blobsize(m_block.miner_tx);

View file

@ -35,23 +35,24 @@ bool test_transaction_generation_and_ring_signature()
std::string add_str = miner_acc3.get_public_address_str();
uint64_t block_reward_without_fee = 0;
uint64_t block_reward = 0;
account_base rv_acc;
rv_acc.generate();
account_base rv_acc2;
rv_acc2.generate();
transaction tx_mine_1;
construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().account_address, miner_acc1.get_keys().account_address, tx_mine_1, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 10, 0, miner_acc1.get_keys().account_address, miner_acc1.get_keys().account_address, tx_mine_1, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_2;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc2.get_keys().account_address, miner_acc2.get_keys().account_address, tx_mine_2, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc2.get_keys().account_address, miner_acc2.get_keys().account_address, tx_mine_2, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_3;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc3.get_keys().account_address, miner_acc3.get_keys().account_address, tx_mine_3, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc3.get_keys().account_address, miner_acc3.get_keys().account_address, tx_mine_3, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_4;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc4.get_keys().account_address, miner_acc4.get_keys().account_address, tx_mine_4, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc4.get_keys().account_address, miner_acc4.get_keys().account_address, tx_mine_4, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_5;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc5.get_keys().account_address, miner_acc5.get_keys().account_address, tx_mine_5, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc5.get_keys().account_address, miner_acc5.get_keys().account_address, tx_mine_5, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4);
transaction tx_mine_6;
construct_miner_tx(0, 0, 0, 0, 0, miner_acc6.get_keys().account_address, miner_acc6.get_keys().account_address, tx_mine_6, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
construct_miner_tx(0, 0, 0, 0, 0, miner_acc6.get_keys().account_address, miner_acc6.get_keys().account_address, tx_mine_6, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4);
//fill inputs entry
typedef tx_source_entry::output_entry tx_output_entry;
@ -136,8 +137,9 @@ bool test_block_creation()
bool r = get_account_address_from_str(adr, "ZxDLGBGXbjo5w51tJkvxEPHFRr7Xft4hf33N8EkJPndoGCqocQF1mzpZqYwXByx5gMbfQuPAAB9vj79EFR6Jwkgu1o3aMQPwJ");
CHECK_AND_ASSERT_MES(r, false, "failed to import");
uint64_t block_reward_without_fee = 0;
uint64_t block_reward = 0;
block b;
r = construct_miner_tx(90, epee::misc_utils::median(szs), 3553616528562147, 33094, 10000000, adr, adr, b.miner_tx, block_reward_without_fee, TRANSACTION_VERSION_PRE_HF4);
r = construct_miner_tx(90, epee::misc_utils::median(szs), 3553616528562147, 33094, 10000000, adr, adr, b.miner_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4);
return r;
}

View file

@ -1778,9 +1778,6 @@ bool gen_wallet_alias_and_unconfirmed_txs::c3(currency::core& c, size_t ev_index
gen_wallet_alias_via_special_wallet_funcs::gen_wallet_alias_via_special_wallet_funcs()
{
// start hardfork from block 0 in order to use extra_alias_entry (allowed only since HF2)
m_hardforks.set_hardfork_height(1, 0);
m_hardforks.set_hardfork_height(2, 0);
REGISTER_CALLBACK_METHOD(gen_wallet_alias_via_special_wallet_funcs, c1);
}
@ -3452,7 +3449,7 @@ bool packing_outputs_on_pos_minting_wallet::c1(currency::core& c, size_t ev_inde
CHECK_AND_ASSERT_MES(blocks_fetched == 1, false, "Incorrect numbers of blocks fetched: " << blocks_fetched);
// (also make sure that unlocked balance is zero)
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "bob_wlt", m_bob_initial_balance + CURRENCY_BLOCK_REWARD, CURRENCY_BLOCK_REWARD + TESTS_DEFAULT_FEE, 0), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "bob_wlt", m_bob_initial_balance + CURRENCY_BLOCK_REWARD, INVALID_BALANCE_VAL, 0), false, "");
// 2. Try to mine a PoS block and defragment some of UTXO
@ -3465,7 +3462,7 @@ bool packing_outputs_on_pos_minting_wallet::c1(currency::core& c, size_t ev_inde
CHECK_AND_ASSERT_MES(blocks_fetched == 2, false, "Incorrect numbers of blocks fetched: " << blocks_fetched);
// (also make sure that only two UTXOs is unlocked)
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", m_alice_initial_balance + CURRENCY_BLOCK_REWARD, CURRENCY_BLOCK_REWARD + TESTS_DEFAULT_FEE, m_single_amount * 2), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", m_alice_initial_balance + CURRENCY_BLOCK_REWARD, INVALID_BALANCE_VAL, m_single_amount * 2), false, "");
// 3. Try to mine a PoS block and defragment with huge decoy set. Make sure block is mined successfully without a defragmentation tx
@ -3479,7 +3476,7 @@ bool packing_outputs_on_pos_minting_wallet::c1(currency::core& c, size_t ev_inde
CHECK_AND_ASSERT_MES(blocks_fetched == 1, false, "Incorrect numbers of blocks fetched: " << blocks_fetched);
// Alice's unlocked balance should consist only of one UTXO
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", m_alice_initial_balance + CURRENCY_BLOCK_REWARD * 2, CURRENCY_BLOCK_REWARD * 2 + TESTS_DEFAULT_FEE, m_single_amount), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", m_alice_initial_balance + CURRENCY_BLOCK_REWARD * 2, INVALID_BALANCE_VAL, m_single_amount), false, "");
// 4. Finally mine a PoS and defragment the last one unlocked UTXO
@ -3492,7 +3489,7 @@ bool packing_outputs_on_pos_minting_wallet::c1(currency::core& c, size_t ev_inde
CHECK_AND_ASSERT_MES(blocks_fetched == 1, false, "Incorrect numbers of blocks fetched: " << blocks_fetched);
// Alice's unlocked balance should be zero
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", m_alice_initial_balance + CURRENCY_BLOCK_REWARD * 3, CURRENCY_BLOCK_REWARD * 3 + TESTS_DEFAULT_FEE, 0), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "alice_wlt", m_alice_initial_balance + CURRENCY_BLOCK_REWARD * 3, INVALID_BALANCE_VAL, 0), false, "");
return true;
}

View file

@ -67,7 +67,7 @@ bool wallet_test::check_balance(currency::core& c, size_t ev_index, const std::v
bool has_aliases = false;
w->scan_tx_pool(has_aliases);
if (!check_balance_via_wallet(*w.get(), get_test_account_name_by_id(pcb.account_index).c_str(), pcb.total_balance, pcb.mined_balance, pcb.unlocked_balance, pcb.awaiting_in, pcb.awaiting_out))
if (!check_balance_via_wallet(*w.get(), get_test_account_name_by_id(pcb.account_index).c_str(), pcb.total_balance, INVALID_BALANCE_VAL, pcb.unlocked_balance, pcb.awaiting_in, pcb.awaiting_out))
return false;
return true;

View file

@ -215,8 +215,8 @@ bool zarcanum_basic_test::c1(currency::core& c, size_t ev_index, const std::vect
uint64_t mined_amount = (batches_to_Alice_count - 1) * COIN;
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*staker_benefeciary_acc_wlt, "staker_benefeciary", mined_amount, mined_amount, mined_amount), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_benefeciary_acc_wlt, "miner_benefeciary", mined_amount, mined_amount, mined_amount), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*staker_benefeciary_acc_wlt, "staker_benefeciary", mined_amount, INVALID_BALANCE_VAL, mined_amount), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*miner_benefeciary_acc_wlt, "miner_benefeciary", mined_amount, INVALID_BALANCE_VAL, mined_amount), false, "");
staker_benefeciary_acc_wlt->transfer(transfer_amount2, bob_wlt->get_account().get_public_address());
@ -234,7 +234,7 @@ bool zarcanum_basic_test::c1(currency::core& c, size_t ev_index, const std::vect
bob_wlt->refresh();
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", transfer_amount2*3, UINT64_MAX, transfer_amount2*3), false, "");
CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt, "Bob", transfer_amount2*3, INVALID_BALANCE_VAL, transfer_amount2*3), false, "");
//try to make pre-zarcanum block after hardfork 4
currency::core_runtime_config rc = alice_wlt->get_core_runtime_config();
@ -367,14 +367,16 @@ bool zarcanum_gen_time_balance::generate(std::vector<test_event_entry>& events)
uint64_t bob_amount = MK_TEST_COINS(15);
MAKE_TX(events, tx_1, alice_acc, bob_acc, bob_amount, blk_1r);
MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_acc, tx_1);
MAKE_NEXT_BLOCK_TX1(events, blk_2__, blk_1r, miner_acc, tx_1);
// check Bob's balance in play time...
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(BOB_ACC_IDX, bob_amount, 0, 0, 0, 0));
REWIND_BLOCKS_N_WITH_TIME(events, blk_2, blk_2__, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
// ... and in gen time
CREATE_TEST_WALLET(bob_wlt, bob_acc, blk_0);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_2, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 5);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_2, 2 * CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 15);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(bob_wlt, bob_amount);
// try to construct tx with only one output (that is wrong for HF4)
@ -399,14 +401,16 @@ bool zarcanum_gen_time_balance::generate(std::vector<test_event_entry>& events)
MAKE_TX_FEE_MIX(events, tx_2, bob_acc, alice_acc, bob_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, nmix, blk_2);
CHECK_AND_ASSERT_MES(tx_2.vout.size() != 1, false, "tx_2.vout.size() = " << tx_2.vout.size());
MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_acc, tx_2);
REWIND_BLOCKS_N_WITH_TIME(events, blk_4, blk_3, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_3, 2);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, alice_wlt, blk_4, 22);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(alice_wlt, alice_amount - 2 * TESTS_DEFAULT_FEE);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_3, 1);
REFRESH_TEST_WALLET_AT_GEN_TIME(events, bob_wlt, blk_4, 11);
CHECK_TEST_WALLET_BALANCE_AT_GEN_TIME(bob_wlt, 0);
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, alice_amount - 2 * TESTS_DEFAULT_FEE, 0, 0, 0, 0));
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, alice_amount - 2 * TESTS_DEFAULT_FEE, alice_amount - 2 * TESTS_DEFAULT_FEE, 0, 0, 0));
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(BOB_ACC_IDX, 0, 0, 0, 0, 0));
@ -422,8 +426,6 @@ zarcanum_pos_block_math::zarcanum_pos_block_math()
bool zarcanum_pos_block_math::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
GENERATE_ACCOUNT(miner_acc);
MAKE_GENESIS_BLOCK(events, blk_0, miner_acc, test_core_time::get_time());
DO_CALLBACK(events, "configure_core"); // necessary to set m_hardforks
@ -602,8 +604,6 @@ zarcanum_in_alt_chain::zarcanum_in_alt_chain()
bool zarcanum_in_alt_chain::generate(std::vector<test_event_entry>& events) const
{
bool r = false;
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
@ -628,7 +628,10 @@ bool zarcanum_in_alt_chain::generate(std::vector<test_event_entry>& events) cons
uint64_t bob_amount = COIN * 100;
MAKE_TX(events, tx_1, miner_acc, bob_acc, bob_amount, blk_3);
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, tx_1);
//make another tx just to create more decoys to fit hf4 rules of 16 decoys
account_base carol_acc; carol_acc.generate();
MAKE_TX(events, tx_1_1, miner_acc, carol_acc, bob_amount, blk_3);
MAKE_NEXT_BLOCK_TX_LIST(events, blk_4, blk_3, miner_acc, std::list<transaction>({ tx_1, tx_1_1 }));
// HF4
// |
@ -712,8 +715,13 @@ bool zarcanum_in_alt_chain::c1(currency::core& c, size_t ev_index, const std::ve
uint64_t transfer_amount = COIN;
uint64_t transfer_fee = TESTS_DEFAULT_FEE * 3;
size_t nmix = 38;
bob_wlt->transfer(transfer_amount, nmix, m_accounts[ALICE_ACC_IDX].get_public_address(), transfer_fee);
size_t nmix = 36;
try {
bob_wlt->transfer(transfer_amount, nmix, m_accounts[ALICE_ACC_IDX].get_public_address(), transfer_fee);
}
catch (...)
{
}
CHECK_AND_FORCE_ASSERT_MES(c.get_pool_transactions_count() == 3, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count());
@ -745,8 +753,6 @@ bool zarcanum_block_with_txs::generate(std::vector<test_event_entry>& events) co
{
// Test idea: make sure Zarcanum PoS block can have txs and the sum of fees is correctly added to the block reward
bool r = false;
uint64_t ts = test_core_time::get_time();
m_accounts.resize(TOTAL_ACCS_COUNT);
account_base& miner_acc = m_accounts[MINER_ACC_IDX]; miner_acc.generate(); miner_acc.set_createtime(ts);
@ -788,14 +794,15 @@ bool zarcanum_block_with_txs::generate(std::vector<test_event_entry>& events) co
//
// after HF4
//
MAKE_NEXT_BLOCK(events, blk_3, blk_2, miner_acc);
MAKE_NEXT_BLOCK(events, blk_3_, blk_2, miner_acc);
MAKE_NEXT_BLOCK(events, blk_3, blk_3_, miner_acc);
DO_CALLBACK_PARAMS(events, "check_hardfork_active", static_cast<size_t>(ZANO_HARDFORK_04_ZARCANUM));
MAKE_TX(events, tx_2, miner_acc, alice_acc, MK_TEST_COINS(200), blk_3);
MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_acc, tx_2);
m_alice_balance += MK_TEST_COINS(200);
REWIND_BLOCKS_N_WITH_TIME(events, blk_4r, blk_4, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW);
REWIND_BLOCKS_N_WITH_TIME(events, blk_4r, blk_4, miner_acc, CURRENCY_MINED_MONEY_UNLOCK_WINDOW+5);
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, m_alice_balance, m_alice_balance, mined_amount, 0, 0));
// then miner sends few coins to Bob via a tx with a big fee amount
@ -805,8 +812,8 @@ bool zarcanum_block_with_txs::generate(std::vector<test_event_entry>& events) co
// and Alice mines a PoS block with this tx -- so Alice is expected to receive the fee
MAKE_NEXT_POS_BLOCK_TX1(events, blk_5, blk_4r, alice_acc, alice_stake_sources, tx_3);
// make sure Alice received both block reward and the fee
uint64_t mined_amount_2 = COIN + fee;
// make sure Alice received block reward but not received the fee
uint64_t mined_amount_2 = COIN /* + fee */;
DO_CALLBACK_PARAMS(events, "check_balance", params_check_balance(ALICE_ACC_IDX, m_alice_balance + mined_amount_2, UINT64_MAX, mined_amount + mined_amount_2, 0, 0));
m_alice_balance += mined_amount_2;

View file

@ -1466,6 +1466,37 @@ TEST(crypto, point_is_zero)
ASSERT_TRUE(p.is_zero());
memset(&p.m_p3, 0, sizeof p.m_p3);
memcpy(&p.m_p3.Y, f_x, sizeof p.m_p3.Y);
memcpy(&p.m_p3.Z, f_x, sizeof p.m_p3.Z);
memcpy(&p.m_p3.T, fancy_p, sizeof p.m_p3.T);
// {0, x, x, P} == {0, 1} (still the identity point)
ASSERT_TRUE(p.is_zero());
//
// negative tests
//
memset(&p.m_p3, 0, sizeof p.m_p3);
// {0, 0, 0, 0} is not a point at all
ASSERT_FALSE(p.is_zero());
memset(&p.m_p3, 0, sizeof p.m_p3);
memcpy(&p.m_p3.Y, f_x, sizeof p.m_p3.Y);
memcpy(&p.m_p3.Z, f_x, sizeof p.m_p3.Z);
memcpy(&p.m_p3.T, fancy_p_plus_1, sizeof p.m_p3.T);
// {0, x, x, !0} is not a valid point (incorrect non-zero T)
ASSERT_FALSE(p.is_zero());
memcpy(&p.m_p3.T, f_x, sizeof p.m_p3.T);
// {0, x, x, x}, while x != 0 is still incorrect point representation
ASSERT_FALSE(p.is_zero());
return true;
}
@ -1588,6 +1619,7 @@ TEST(crypto, schnorr_sig)
return true;
}
TEST(crypto, point_negation)
{
ASSERT_EQ(c_point_0, -c_point_0);
@ -1620,6 +1652,252 @@ TEST(crypto, point_negation)
}
TEST(crypto, scalar_get_bits)
{
scalar_t x = scalar_t::random();
for(size_t i = 0; i < 256; ++i)
ASSERT_EQ(x.get_bits(i, 0), 0);
for(size_t i = 0; i < 256; ++i)
ASSERT_EQ(x.get_bits(i, std::min((size_t)255, i + 65)), 0);
ASSERT_EQ(x.get_bits(0, 64), x.m_u64[0]);
ASSERT_EQ(x.get_bits(64, 64), x.m_u64[1]);
ASSERT_EQ(x.get_bits(128, 64), x.m_u64[2]);
ASSERT_EQ(x.get_bits(192, 64), x.m_u64[3]);
uint64_t high_32_bits = x.m_u64[3] >> 32;
ASSERT_EQ(x.get_bits(192+32, 32), high_32_bits);
for(size_t i = 33; i <= 64; ++i)
ASSERT_EQ(x.get_bits(192+32, i), high_32_bits);
for(size_t i = 0; i < 10000; ++i)
{
scalar_t b = scalar_t::random();
scalar_t x = scalar_t::random();
size_t bit_index_from = b.m_s[5];
size_t bits_count = b.m_s[6] % 65; // [0; 64] are allowed
uint64_t extracted_bits = 0;
for(size_t j = 0; j < bits_count; ++j)
{
if (bit_index_from + j <= 255 && x.get_bit(bit_index_from + j))
extracted_bits |= 1ull << j;
}
if (extracted_bits != x.get_bits(bit_index_from, bits_count))
{
std::cout << "i: " << i << ", bit_index_from: " << bit_index_from << ", bits_count: " << bits_count << ENDL
<< "extracted_bits: " << extracted_bits << ", get_bits(): " << x.get_bits(bit_index_from, bits_count);
ASSERT_TRUE(false);
}
}
return true;
}
TEST(crypto, scalarmult_base_vartime)
{
auto check_for_x = [&](const scalar_t& x) -> bool {
point_t P, P2;
ge_scalarmult_base_vartime(&P.m_p3, x.m_s);
ge_scalarmult_base(&P2.m_p3, x.m_s);
return (P - P2).is_zero();
};
ASSERT_TRUE(check_for_x(c_scalar_0));
ASSERT_TRUE(check_for_x(c_scalar_1));
ASSERT_TRUE(check_for_x(c_scalar_1div8));
ASSERT_TRUE(check_for_x(c_scalar_Lm1));
ASSERT_TRUE(check_for_x(c_scalar_L));
for(size_t i = 0; i < 1000; ++i)
{
scalar_t x = scalar_t::random();
ASSERT_TRUE(check_for_x(x));
}
return true;
}
template<typename CT>
bool crypto_msm_runner(size_t N, size_t low_bits_to_clear, size_t high_bits_to_clear)
{
scalar_vec_t g_scalars, h_scalars;
g_scalars.resize_and_make_random(N);
h_scalars.resize_and_make_random(N);
if (N > 4)
{
g_scalars[0] = c_scalar_Lm1; // always include the max and the min
h_scalars[0] = c_scalar_Lm1;
g_scalars[1] = 0;
h_scalars[1] = 0;
}
point_t sum = c_point_0;
for(size_t i = 0; i < N; ++i)
{
for(size_t bit_index = 0; bit_index < low_bits_to_clear; ++bit_index)
{
g_scalars[i].clear_bit(bit_index);
h_scalars[i].clear_bit(bit_index);
}
for(size_t bit_index = 256 - high_bits_to_clear; bit_index < 256; ++bit_index)
{
g_scalars[i].clear_bit(bit_index);
h_scalars[i].clear_bit(bit_index);
}
sum += g_scalars[i] * CT::get_generator(false, i) + h_scalars[i] * CT::get_generator(true, i);
}
//TIME_MEASURE_START(t);
bool r = msm_and_check_zero<CT>(g_scalars, h_scalars, -sum);
//TIME_MEASURE_FINISH(t);
return r;
}
TEST(crypto, msm)
{
// test the default msm_and_check_zero correctness
bool r = false;
for(size_t N = 1; N <= 128; ++N)
{
std::cout << "N = " << N << ENDL;
r = crypto_msm_runner<bpp_crypto_trait_Zarcanum>(N, 0, 0);
ASSERT_TRUE(r);
r = crypto_msm_runner<bpp_crypto_trait_ZC_out>(N, 0, 0);
ASSERT_TRUE(r);
}
for(size_t i = 0; i <= 128; ++i)
{
std::cout << "i = " << i << ENDL;
r = crypto_msm_runner<bpp_crypto_trait_Zarcanum>(128, i, 0);
ASSERT_TRUE(r);
r = crypto_msm_runner<bpp_crypto_trait_Zarcanum>(128, 0, i);
ASSERT_TRUE(r);
r = crypto_msm_runner<bpp_crypto_trait_ZC_out>(256, i, 0);
ASSERT_TRUE(r);
r = crypto_msm_runner<bpp_crypto_trait_ZC_out>(256, 0, i);
ASSERT_TRUE(r);
}
return true;
}
inline std::ostream &operator <<(std::ostream &o, const crypto::ge_precomp v)
{
o << "{{";
for(size_t i = 0; i < 9; ++i)
o << v.yplusx[i] << ", ";
o << v.yplusx[9] << "}, {";
for(size_t i = 0; i < 9; ++i)
o << v.yminusx[i] << ", ";
o << v.yminusx[9] << "}, {";
for(size_t i = 0; i < 9; ++i)
o << v.xy2d[i] << ", ";
o << v.xy2d[9] << "}}";
return o;
}
bool calc_and_print_generator_precomp(const point_pc_t& generator, const char* generator_var_name)
{
precomp_data_t precomp_data = {};
construct_precomp_data(precomp_data, generator);
std::cout << " const precomp_data_t " << generator_var_name << "_precomp_data = {" << ENDL;
for(size_t i = 0; i < 32; ++i)
{
std::cout << " {" << ENDL;
for(size_t j = 0; j < 8; ++j)
std::cout << " " << precomp_data[i][j] << (j != 7 ? "," : "" ) << ENDL;
std::cout << " }" << (i != 31 ? "," : "" ) << ENDL;
}
std::cout << " };" << ENDL;
return true;
}
TEST(print, generators_precomp)
{
#define CALC_PRECOMP(G) calc_and_print_generator_precomp(G, #G)
CALC_PRECOMP(c_point_H);
CALC_PRECOMP(c_point_H2);
CALC_PRECOMP(c_point_U);
CALC_PRECOMP(c_point_X);
CALC_PRECOMP(c_point_H_plus_G);
CALC_PRECOMP(c_point_H_minus_G);
return true;
#undef CALC_PRECOMP
}
bool check_generator_precomp(const point_pc_t& generator, const char* generator_var_name)
{
point_t generator_pt = generator; // to avoid using precomputed data in scalar multiplications
point_t random_point = hash_helper_t::hp(scalar_t::random());
point_t A = generator_pt;
for(size_t i = 0; i < 32; ++i)
{
point_t B = c_point_0;
for(size_t j = 0; j < 8; ++j)
{
B += A;
// restore ge_p3 from ge_precomp using native NaCl functions...
point_t restored_pt{};
ge_p1p1 p1p1{};
ge_madd(&p1p1, &random_point.m_p3, &((*generator.m_precomp_data_p)[i][j]));
ge_p1p1_to_p3(&restored_pt.m_p3, &p1p1);
restored_pt -= random_point;
// ...and compare it with the calculated one
if (B != restored_pt)
{
std::cout << "ERROR: " << generator_var_name << ", i: " << i << ", j: " << j << ENDL;
return false;
}
}
if (i != 31)
A.modify_mul_pow_2(8);
}
std::cout << " " << std::left << std::setw(32) << generator_var_name << " OK" << ENDL;
return true;
}
TEST(crypto, generators_precomp)
{
#define CHECK_PRECOMP(G) ASSERT_TRUE(check_generator_precomp(G, #G))
CHECK_PRECOMP(c_point_H);
CHECK_PRECOMP(c_point_H2);
CHECK_PRECOMP(c_point_U);
CHECK_PRECOMP(c_point_X);
CHECK_PRECOMP(c_point_H_plus_G);
CHECK_PRECOMP(c_point_H_minus_G);
return true;
#undef CHECK_PRECOMP
}
//
// test's runner
//

View file

@ -1,5 +1,5 @@
// Copyright (c) 2022 Zano Project (https://zano.org/)
// Copyright (c) 2022 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2022-2024 Zano Project (https://zano.org/)
// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
@ -166,11 +166,11 @@ TEST(clsag, bad_pub_keys)
ASSERT_TRUE(cc.generate());
ASSERT_TRUE(cc.verify());
// torsion component in K1 should not affect protocol
// torsion component in K1 should break the protocol
cc = cc_orig;
ASSERT_TRUE(cc.generate());
cc.sig.K1 = (point_t(cc.sig.K1) + tor).to_public_key();
ASSERT_TRUE(cc.verify());
ASSERT_FALSE(cc.verify());
// torsion component in stealth_address for secret_index (i.e. for P = xG) must break the protocol
// 1
@ -399,9 +399,9 @@ TEST(clsag_ggx, basics)
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// CLSAG GGXG
// CLSAG GGXG (eventually not used in Zano)
//
/*
struct clsag_ggxg_sig_check_t
{
crypto::hash prefix_hash;
@ -537,7 +537,7 @@ TEST(clsag_ggxg, basics)
ASSERT_TRUE(cc.verify());
return true;
}
}*/
///////////////////////////////////////////////////////////////////////////////////////////////////
//

View file

@ -2,8 +2,61 @@
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <numeric>
TEST(crypto, primitives)
uint64_t get_bits_v1(const scalar_t& s, uint8_t bit_index_first, uint8_t bits_count)
{
if (bits_count == 0 || bits_count > 64)
return 0;
unsigned int bit_index_last = bit_index_first + bits_count - 1;
if (bit_index_last > 255)
bit_index_last = 255;
uint64_t result_mask = ((1ull << (bits_count - 1)) - 1) << 1 | 1; // (just because 1ull << 64 in undefined behaviour, not a 0 as one would expect)
uint64_t result = s.m_u64[bit_index_first >> 6] >> (bit_index_first & 63);
if (bits_count > (bit_index_last & 63) + 1)
result |= s.m_u64[bit_index_last >> 6] << (bits_count - (bit_index_last & 63) - 1);
return result & result_mask;
}
TEST(crypto, ge_precomp)
{
//precomp_data_t G_precomp = {};
//construct_precomp_data(G_precomp, c_point_G);
//std::cout << "size of G_precomp: " << sizeof G_precomp << " bytes" << ENDL;
//for(size_t i = 0; i < 32; ++i)
// for(size_t j = 0; j < 8; ++j)
// std::cout << "i: " << i << ", j: " << j << ", precomp: " << ENDL << G_precomp[i][j] << ENDL;
precomp_data_t H_precomp = {};
construct_precomp_data(H_precomp, c_point_H);
auto check_for_x = [&](const scalar_t& x) -> bool {
point_t P;
ge_scalarmult_precomp_vartime(&P.m_p3, H_precomp, x.m_s);
return P == x * c_point_H;
};
ASSERT_TRUE(check_for_x(c_scalar_0));
ASSERT_TRUE(check_for_x(c_scalar_1));
ASSERT_TRUE(check_for_x(c_scalar_1div8));
ASSERT_TRUE(check_for_x(c_scalar_Lm1));
ASSERT_TRUE(check_for_x(c_scalar_L));
for(size_t i = 0; i < 1000; ++i)
{
scalar_t x = scalar_t::random();
ASSERT_TRUE(check_for_x(x));
}
return true;
}
TEST(perf, primitives)
{
struct helper
{
@ -46,6 +99,44 @@ TEST(crypto, primitives)
#define HASH_64_VEC(vec_var_name) hash_64(vec_var_name.data(), vec_var_name.size() * sizeof(vec_var_name[0]))
LOG_PRINT_L0(ENDL << "hash functions:");
struct run_cn_fash_hash
{
static uint64_t run(timer_t& t, size_t rounds, size_t data_size)
{
std::vector<size_t> rnd_indecies;
helper::make_rnd_indicies(rnd_indecies, rounds);
struct bytes64
{
unsigned char b[64];
};
std::vector<bytes64> scalars_64(rounds);
for (size_t i = 0; i < scalars_64.size(); ++i)
crypto::generate_random_bytes(sizeof(bytes64), scalars_64[i].b);
std::vector<hash> results(rounds);
t.start();
for (size_t i = 0; i < rounds; ++i)
{
results[i] = cn_fast_hash(scalars_64[rnd_indecies[i]].b, 64);
}
t.stop();
return HASH_64_VEC(results);
};
};
run("cn_fast_hash(64 bytes)", 1000, [](timer_t& t, size_t rounds) {
return run_cn_fash_hash::run(t, rounds, 64ull);
});
run("cn_fast_hash(2048 bytes)", 1000, [](timer_t& t, size_t rounds) {
return run_cn_fash_hash::run(t, rounds, 2048ull);
});
LOG_PRINT_L0(ENDL << "native crypto primitives:");
run("sc_reduce", 30000, [](timer_t& t, size_t rounds) {
@ -239,7 +330,7 @@ TEST(crypto, primitives)
return HASH_64_VEC(points_cached);
});
run("ge_add(p3 + p3)", 50000, [](timer_t& t, size_t rounds) {
run("ge_add(p1p1 = p3 + cached)", 50000, [](timer_t& t, size_t rounds) {
std::vector<size_t> rnd_indecies;
helper::make_rnd_indicies(rnd_indecies, rounds);
std::vector<ge_cached> points_cached(rounds);
@ -454,7 +545,7 @@ TEST(crypto, primitives)
return HASH_64_VEC(points_p3);
});
run("ge_scalarmult_base()", 5000, [](timer_t& t, size_t rounds) {
run("ge_scalarmult_base()", 10000, [](timer_t& t, size_t rounds) {
std::vector<size_t> rnd_indecies;
helper::make_rnd_indicies(rnd_indecies, rounds);
@ -479,6 +570,87 @@ TEST(crypto, primitives)
return HASH_64_VEC(points_p3);
});
run("construct_precomp_data()", 300, [](timer_t& t, size_t rounds) {
std::vector<size_t> rnd_indecies;
helper::make_rnd_indicies(rnd_indecies, rounds);
unsigned char s[32] = {};
std::vector<point_t> random_points(rounds);
for (size_t i = 0; i < rounds; ++i)
{
s[0] = i;
ge_p2 p2;
ge_fromfe_frombytes_vartime(&p2, s);
ge_p2_to_p3(&random_points[i].m_p3, &p2);
}
std::vector<ge_p3> points_p3(rounds);
precomp_data_t precomp_data;
uint64_t result = 0;
t.start();
for (size_t i = 0; i < rounds; ++i)
{
construct_precomp_data(precomp_data, random_points[rnd_indecies[i]]);
result ^= (precomp_data[1][1].xy2d[1] + precomp_data[31][7].xy2d[9]);
}
t.stop();
return result;
});
run("ge_scalarmult_precomp_vartime()", 10000, [](timer_t& t, size_t rounds) {
std::vector<size_t> rnd_indecies;
helper::make_rnd_indicies(rnd_indecies, rounds);
scalar_t x;
x.make_random();
std::vector<crypto::ec_scalar> scalars(rounds);
for (size_t i = 0; i < rounds; ++i)
{
scalar_t x = x + x + x;
memcpy(&scalars[i].data, x.data(), 32);
}
precomp_data_t precomp_data;
construct_precomp_data(precomp_data, x * c_point_X);
std::vector<ge_p3> points_p3(rounds);
t.start();
for (size_t i = 0; i < rounds; ++i)
{
ge_scalarmult_precomp_vartime(&points_p3[i], precomp_data, (const unsigned char*)&scalars[rnd_indecies[i]]);
}
t.stop();
return HASH_64_VEC(points_p3);
});
run("ge_scalarmult_base_vartime()", 10000, [](timer_t& t, size_t rounds) {
std::vector<size_t> rnd_indecies;
helper::make_rnd_indicies(rnd_indecies, rounds);
scalar_t x;
x.make_random();
std::vector<crypto::ec_scalar> scalars(rounds);
for (size_t i = 0; i < rounds; ++i)
{
scalar_t x = x + x + x;
memcpy(&scalars[i].data, x.data(), 32);
}
std::vector<ge_p3> points_p3(rounds);
t.start();
for (size_t i = 0; i < rounds; ++i)
{
ge_scalarmult_base_vartime(&points_p3[i], (const unsigned char*)&scalars[rnd_indecies[i]]);
}
t.stop();
return HASH_64_VEC(points_p3);
});
run("ge_mul8_p3()", 5000, [](timer_t& t, size_t rounds) {
std::vector<size_t> rnd_indecies;
helper::make_rnd_indicies(rnd_indecies, rounds);
@ -662,5 +834,402 @@ TEST(crypto, primitives)
return HASH_64_VEC(result);
});
run("get_bits x 10", 20000, [](timer_t& t, size_t rounds) {
std::vector<size_t> rnd_indecies;
helper::make_rnd_indicies(rnd_indecies, rounds);
scalar_vec_t data;
data.resize_and_make_random(rounds);
std::vector<uint64_t> result(rounds);
t.start();
for (size_t i = 0; i < rounds; ++i)
{
auto& x = data[rnd_indecies[i]];
result[i] =
x.get_bits(x.m_s[11], x.m_s[21] % 65) ^
x.get_bits(x.m_s[12], x.m_s[22] % 65) ^
x.get_bits(x.m_s[13], x.m_s[23] % 65) ^
x.get_bits(x.m_s[14], x.m_s[24] % 65) ^
x.get_bits(x.m_s[15], x.m_s[25] % 65) ^
x.get_bits(x.m_s[16], x.m_s[26] % 65) ^
x.get_bits(x.m_s[17], x.m_s[27] % 65) ^
x.get_bits(x.m_s[18], x.m_s[28] % 65) ^
x.get_bits(x.m_s[19], x.m_s[29] % 65) ^
x.get_bits(x.m_s[20], x.m_s[30] % 65);
}
t.stop();
return HASH_64_VEC(result);
});
return true;
} // TEST
////////////////////////////////////////////////////////////////////////////////
///////////////// v3
///////////////// v4
template<typename CT>
bool msm_and_check_zero_pippenger_v4(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, size_t c)
{
// TODO: with c = 8 and with direct access got much worse result than with c = 7 and get_bits(), consider checking again for bigger datasets (N>256)
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
CHECK_AND_ASSERT_MES(c < 10, false, "c is too big");
size_t C = 1ull << c;
// k_max * c + (c-1) >= max_bit_idx
//
// max_bit_idx - (c - 1) max_bit_idx - (c - 1) + (c - 1) max_bit_idx
// k_max = ceil ( --------------------- ) = floor ( ------------------------------ ) = floor ( ----------- )
// c c c
const size_t b = 253; // the maximum number of bits in x https://eprint.iacr.org/2022/999.pdf TODO: we may also scan for maximum bit used in all the scalars if all the scalars are small
const size_t max_bit_idx = b - 1;
const size_t k_max = max_bit_idx / c;
const size_t K = k_max + 1;
std::unique_ptr<point_t[]> buckets( new point_t[C * K] );
std::vector<bool> buckets_inited(C * K);
// first loop, calculate partial bucket sums
for (size_t n = 0; n < g_scalars.size(); ++n)
{
for (size_t k = 0; k < K; ++k)
{
uint64_t l = g_scalars[n].get_bits(k * c, c); // l in [0; 2^c-1]
if (l != 0)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
buckets[bucket_id] += CT::get_generator(false, n);
else
{
buckets[bucket_id] = CT::get_generator(false, n);
buckets_inited[bucket_id] = true;
}
}
}
}
for (size_t n = 0; n < h_scalars.size(); ++n)
{
for (size_t k = 0; k < K; ++k)
{
uint64_t l = h_scalars[n].get_bits(k * c, c); // l in [0; 2^c-1]
if (l != 0)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
buckets[bucket_id] += CT::get_generator(true, n);
else
{
buckets[bucket_id] = CT::get_generator(true, n);
buckets_inited[bucket_id] = true;
}
}
}
}
// the second loop
// S[l, k] = S[l-1, k] + B[l, k]
// G[k] = sum{1..C-1} S[l, k]
std::unique_ptr<point_t[]> Sk( new point_t[K] );
std::vector<bool> Sk_inited(K);
std::unique_ptr<point_t[]> Gk( new point_t[K] );
std::vector<bool> Gk_inited(K);
for (size_t l = C - 1; l > 0; --l)
{
for (size_t k = 0; k < K; ++k)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
{
if (Sk_inited[k])
Sk[k] += buckets[bucket_id];
else
{
Sk[k] = buckets[bucket_id];
Sk_inited[k] = true;
}
}
if (Sk_inited[k])
{
if (Gk_inited[k])
Gk[k] += Sk[k];
else
{
Gk[k] = Sk[k];
Gk_inited[k] = true;
}
}
}
}
// the third loop: Horners rule
point_t result = Gk_inited[K - 1] ? Gk[K - 1] : c_point_0;
for (size_t k = K - 2; k != SIZE_MAX; --k)
{
result.modify_mul_pow_2(c);
if (Gk_inited[k])
result += Gk[k];
}
result += summand;
if (!result.is_zero())
{
LOG_PRINT_L0("msm result is non zero: " << result);
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////////////////
//template<typename CT>
//struct mes_msm_and_check_zero_pippenger_v1
//{
// static bool msm_and_check_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, size_t c)
// {
// return msm_and_check_zero_pippenger_v1<CT>(g_scalars, h_scalars, summand, c);
// }
//};
//
//template<typename CT>
//struct mes_msm_and_check_zero_pippenger_v2
//{
// static bool msm_and_check_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, size_t c)
// {
// return msm_and_check_zero_pippenger_v2<CT>(g_scalars, h_scalars, summand, c);
// }
//};
template<typename CT>
struct mes_msm_and_check_zero_pippenger_v3
{
static bool msm_and_check_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, size_t c)
{
return msm_and_check_zero_pippenger_v3<CT>(g_scalars, h_scalars, summand, c);
}
};
template<typename CT>
struct mes_msm_and_check_zero_pippenger_v4
{
static bool msm_and_check_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, size_t c)
{
return msm_and_check_zero_pippenger_v4<CT>(g_scalars, h_scalars, summand, c);
}
};
struct pme_runner_i
{
virtual ~pme_runner_i() {}
virtual bool iteration(bool warmup) = 0;
};
template<size_t N, typename CT, template<typename> typename selector_t>
struct pme_runner_t : public pme_runner_i
{
pme_runner_t(const char* testname_, size_t pip_partition_bits_c)
: testname(testname_)
, pip_partition_bits_c(pip_partition_bits_c)
{
testname += std::string(", ") + std::string(typeid(selector_t<CT>).name()).erase(0, 11) + std::string(", c = ") + epee::string_tools::num_to_string_fast(pip_partition_bits_c);
std::cout << testname << ENDL;
}
virtual ~pme_runner_t()
{
if (timings.empty())
return;
uint64_t median = 0;
auto median_it = timings.begin() + timings.size() / 2;
std::nth_element(timings.begin(), median_it, timings.end());
median = *median_it;
if (timings.size() % 2 == 0)
{
auto max_it = std::max_element(timings.begin(), median_it);
median = (median + *max_it) / 2;
}
uint64_t total_time = std::accumulate(timings.begin(), timings.end(), 0);
std::cout << std::left << std::setw(100) << testname << " : " << std::setw(5) << median << " (median), " << std::setw(5) << total_time / timings.size() << " (avg), mcs" << ENDL;
}
virtual bool iteration(bool warmup)
{
scalar_vec_t g_scalars, h_scalars;
g_scalars.resize_and_make_random(N);
g_scalars[0] = c_scalar_Lm1;
//std::cout << "bit 251: " << g_scalars[0].get_bit(251) << ", bit 252: " << g_scalars[0].get_bit(252) << ENDL;
h_scalars.resize_and_make_random(N);
point_t sum = c_point_0;
for(size_t i = 0; i < N; ++i)
{
//g_scalars[i].m_u64[3] = 0;
//h_scalars[i].m_u64[3] = 0;
//g_scalars[i].m_s[31] = 0;
//h_scalars[i].m_s[31] = 0;
sum += g_scalars[i] * CT::get_generator(false, i) + h_scalars[i] * CT::get_generator(true, i);
}
TIME_MEASURE_START(t);
bool r = selector_t<CT>::msm_and_check_zero(g_scalars, h_scalars, -sum, pip_partition_bits_c);
TIME_MEASURE_FINISH(t);
ASSERT_TRUE(r);
if (!warmup)
timings.push_back(t);
return true;
}
std::vector<uint64_t> timings;
std::string testname;
size_t pip_partition_bits_c;
};
TEST(perf, msm)
{
bool r = false;
std::deque<std::unique_ptr<pme_runner_i>> runners;
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 1));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 2));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 3));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 4));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 5));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 6));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 7));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 8));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 9));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 1));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 2));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 3));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 4));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 5));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 6));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 7));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 8));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 9));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 1));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 2));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 3));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 4));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 5));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 6));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 7));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 8));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v2> >("Zarcanum, BPPE, 128", 9));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 1));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 2));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 3));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 4));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 5));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 6));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 7));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 8));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v2> >("ZC out, BPP, 256", 9));
runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v3> >("Zarcanum, BPPE, 128 +++++++++++", 7));
runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v3> >("ZC out, BPP, 256 +++++++++++", 7));
runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v4> >("Zarcanum, BPPE, 128 ###########", 7));
runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v4> >("ZC out, BPP, 256 ###########", 7));
//runners.emplace_front(std::make_unique< pme_runner_t<128, bpp_crypto_trait_Zarcanum, mes_msm_and_check_zero_pippenger_v1> >("Zarcanum, BPPE, 128", 7));
//runners.emplace_front(std::make_unique< pme_runner_t<256, bpp_crypto_trait_ZC_out, mes_msm_and_check_zero_pippenger_v1> >("ZC out, BPP, 256", 7));
std::cout << "warm up..." << ENDL;
size_t runs_count = 30;
for(size_t k = 0; k < runs_count; ++k)
{
for(auto& runner : runners)
ASSERT_TRUE(runner->iteration(true));
}
runs_count = 200;
for(size_t k = 0; k < runs_count; ++k)
{
for(auto& runner : runners)
ASSERT_TRUE(runner->iteration(false));
size_t done_percent = 100 * k / runs_count;
if (100 * (k + 1) / runs_count > done_percent && done_percent % 5 == 0)
std::cout << done_percent << " %" << ENDL;
}
return true;
}
template<typename T>
bool perf_generators_runner(const T& generator, const char* title)
{
const size_t warmup_rounds = 20;
const size_t rounds = 500;
const size_t inner_rounds = 128;
uint64_t h = 0;
std::vector<uint64_t> timings;
size_t N = 1024;
scalar_vec_t scalars;
scalars.resize_and_make_random(N);
std::vector<point_t> points(N);
for(size_t i = 0; i < warmup_rounds; ++i)
for(size_t j = 0; j < inner_rounds; ++j)
points[(i + j) % N] = scalars[(i + j) % N] * generator;
h = hash_64(points.data(), points.size() * sizeof(point_t));
for(size_t i = 0; i < rounds; ++i)
{
TIME_MEASURE_START(t);
for(size_t j = 0; j < inner_rounds; ++j)
points[(i + j) % N] = scalars[(i + j) % N] * generator;
TIME_MEASURE_FINISH(t);
timings.push_back(t);
}
h ^= hash_64(points.data(), points.size() * sizeof(point_t));
std::cout << std::left << std::setw(20) << title << " : " << std::setw(5) << std::fixed << std::setprecision(1) << (double)epee::misc_utils::median(timings) / inner_rounds << " mcs, hash = " << h << ENDL;
return true;
}
TEST(perf, generators)
{
#define TEST_GENERATOR(G) ASSERT_TRUE(perf_generators_runner(G, #G))
TEST_GENERATOR(c_point_0);
TEST_GENERATOR(c_point_G);
TEST_GENERATOR(c_point_H);
TEST_GENERATOR(c_point_H2);
TEST_GENERATOR(c_point_U);
TEST_GENERATOR(c_point_X);
TEST_GENERATOR(c_point_H_plus_G);
TEST_GENERATOR(c_point_H_minus_G);
return true;
}

View file

@ -0,0 +1,43 @@
// Copyright (c) 2019 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <algorithm>
#include "gtest/gtest.h"
#include "wallet/decoy_selection.h"
TEST(decoy_selection_test, decoy_selection_test)
{
const uint64_t test_scale_size = 20000;
decoy_selection_generator dsg;
dsg.init(test_scale_size - 1);
std::map<uint64_t, uint64_t> hits;
//std::vector<uint64_t> hits(test_scale_size, 0);
// while (true)
// {
// std::vector<uint64_t> decoys = dsg.generate_distribution(15);
// for (auto d : decoys)
// {
// hits[d]++;
// }
//
// if (hits[10] > 500)
// break;
//
// }
// std::stringstream ss;
// for (auto it = hits.begin(); it != hits.end(); it++)
// {
// //if (hits[i] != 0)
// {
// ss << it->first << ", " << it->second << ENDL;
// }
// }
// epee::file_io_utils::save_string_to_file("distribution.csv", ss.str());
}

View file

@ -69,8 +69,81 @@ TEST(fork_choice_rule_test, fork_choice_rule_test_1)
ASSERT_FALSE(res);
res = if_alt_chain_stronger(200000, 14000);
ASSERT_TRUE(res);
}
bool if_alt_chain_stronger_hf4(const currency::wide_difficulty_type& pos, const currency::wide_difficulty_type& pow)
{
currency::difficulties main_cumul_diff;
main_cumul_diff.pos_diff.assign("1605973467987652534120344647");
main_cumul_diff.pow_diff.assign("3011264554002844981");
currency::difficulties alt_cumul_diff;
alt_cumul_diff.pow_diff = pow;
alt_cumul_diff.pos_diff = pos;
currency::wide_difficulty_type difficulty_pos_at_split_point = main_cumul_diff.pos_diff;
currency::wide_difficulty_type difficulty_pow_at_split_point = main_cumul_diff.pow_diff;
boost::multiprecision::uint1024_t main = currency::get_a_to_b_relative_cumulative_difficulty_hf4(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff);
boost::multiprecision::uint1024_t alt = currency::get_a_to_b_relative_cumulative_difficulty_hf4(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff);
if (alt > main)
return true;
return false;
}
TEST(fork_choice_rule_test, fork_choice_rule_test_hf4)
{
std::stringstream ss;
currency::wide_difficulty_type pos_start, pos_end, pos_step, pos_diveder;
pos_start.assign("16059734679876525341203446");
pos_end.assign ("16059734679876525341203446400");
pos_step.assign ("50000000000000000000000000");
pos_diveder.assign("100000000000000000000000");
currency::wide_difficulty_type pow_start, pow_end, pow_step, pow_diveder;
pow_start.assign("301126455400284498");
pow_end.assign ("30112645540028449810");
pow_step.assign ("500000000000000000");
pow_diveder.assign("1000000000000000");
for (currency::wide_difficulty_type pos = pos_start; pos < pos_end; pos += pos_step)
{
for (currency::wide_difficulty_type pow = pow_start; pow < pow_end; pow += pow_step)
{
bool r = if_alt_chain_stronger_hf4(pos, pow);
if(r)
ss << pos/ pos_diveder << "\t" << pow / pow_diveder << std::endl;
//ss << pos << "\t" << pow << "\t" << (r ? "1" : "0") << std::endl;
}
}
bool r = epee::file_io_utils::save_string_to_file("stat_hf4.txt", ss.str());
bool res = false;
res = if_alt_chain_stronger_hf4(1000000, 1000);
ASSERT_FALSE(res);
res = if_alt_chain_stronger_hf4(1000000, 1500);
ASSERT_TRUE(res);
res = if_alt_chain_stronger_hf4(800000, 1700);
ASSERT_FALSE(res);
res = if_alt_chain_stronger_hf4(800000, 2000);
ASSERT_TRUE(res);
res = if_alt_chain_stronger_hf4(600000, 2200);
ASSERT_FALSE(res);
res = if_alt_chain_stronger_hf4(600000, 2800);
ASSERT_TRUE(res);
res = if_alt_chain_stronger_hf4(400000, 3999);
ASSERT_FALSE(res);
res = if_alt_chain_stronger_hf4(400000, 4001);
ASSERT_TRUE(res);
res = if_alt_chain_stronger_hf4(200000, 7000);
ASSERT_FALSE(res);
res = if_alt_chain_stronger_hf4(200000, 7700);
ASSERT_TRUE(res);
res = if_alt_chain_stronger_hf4(200000, 7000);
ASSERT_FALSE(res);
res = if_alt_chain_stronger_hf4(200000, 7700);
ASSERT_TRUE(res);
res = if_alt_chain_stronger_hf4(100000, 10000);
ASSERT_FALSE(res);
res = if_alt_chain_stronger_hf4(200000, 14000);
ASSERT_TRUE(res);
}

View file

@ -9,6 +9,35 @@
#include "misc_language.h"
namespace epee::misc_utils
{
// old impelementation that uses std::sort
template<class type_vec_type>
type_vec_type old_median(std::vector<type_vec_type> &v)
{
//CRITICAL_REGION_LOCAL(m_lock);
if(v.empty())
return boost::value_initialized<type_vec_type>();
if(v.size() == 1)
return v[0];
size_t n = (v.size()) / 2;
std::sort(v.begin(), v.end());
//nth_element(v.begin(), v.begin()+n-1, v.end());
if(v.size()%2)
{//1, 3, 5...
return v[n];
}else
{//2, 4, 6...
return (v[n-1] + v[n])/2;
}
}
} // namespace epee::misc_utils
//------------------------------------------------------------------------------
bool test_median(const std::vector<uint64_t>& v_)
{
std::vector<uint64_t> v(v_);
@ -21,8 +50,9 @@ bool test_median(const std::vector<uint64_t>& v_)
}
uint64_t m1 = epee::misc_utils::median(v);
uint64_t m2 = mh.get_median();
if (m1 != m2)
return false;
uint64_t m3 = epee::misc_utils::old_median(v);
CHECK_AND_ASSERT_MES(m1 == m2, false, "m1 != m2");
CHECK_AND_ASSERT_MES(m2 == m3, false, "m2 != m3");
return true;
}
@ -100,4 +130,4 @@ TEST(median_helper_test, median_helper_test)
mh.scan_items(cb, cb_finalizer);
}
}

View file

@ -32,8 +32,8 @@ create_desktop_icon()
echo GenericName=Zano | tee -a $target_file_name > /dev/null
echo Comment=Privacy blockchain | tee -a $target_file_name > /dev/null
echo Icon=${out_dir}/Zano.png | tee -a $target_file_name > /dev/null
echo Exec=$APPIMAGE --deeplink-params=%u | tee -a $target_file_name > /dev/null
echo Terminal=true | tee -a $target_file_name > /dev/null
echo Exec=$APPIMAGE --deeplink-params=\\\"%u\\\" | tee -a $target_file_name > /dev/null
echo Terminal=false | tee -a $target_file_name > /dev/null
echo Type=Application | tee -a $target_file_name > /dev/null
echo "Categories=Qt;Utility;" | tee -a $target_file_name > /dev/null
echo "MimeType=x-scheme-handler/zano;" | tee -a $target_file_name > /dev/null

View file

@ -60,7 +60,7 @@ fi
# copy all necessary libs into the bundle in order to workaround El Capitan's SIP restrictions
mkdir -p Zano.app/Contents/Frameworks/boost_libs
cp -R "$ZANO_BOOST_LIBS_PATH/" Zano.app/Contents/Frameworks/boost_libs/
cp -R $ZANO_BOOST_LIBS_PATH/*.dylib Zano.app/Contents/Frameworks/boost_libs/
if [ $? -ne 0 ]; then
echo "Failed to cp workaround to MacOS"
exit 1
@ -84,8 +84,7 @@ source ../../../utils/macosx_fix_boost_libs_path.sh
fix_boost_libs_in_binary @executable_path/../Frameworks/boost_libs Zano.app/Contents/MacOS/Zano
fix_boost_libs_in_binary @executable_path/../Frameworks/boost_libs Zano.app/Contents/MacOS/simplewallet
fix_boost_libs_in_binary @executable_path/../Frameworks/boost_libs Zano.app/Contents/MacOS/zanod
fix_boost_libs_in_libs @executable_path/../Frameworks/boost_libs Zano.app/Contents/Frameworks/boost_libs
#fix_boost_libs_in_libs @executable_path/../Frameworks/boost_libs Zano.app/Contents/Frameworks/boost_libs
"$ZANO_QT_PATH/clang_64/bin/macdeployqt" Zano.app
@ -95,6 +94,8 @@ if [ $? -ne 0 ]; then
fi
rm -rf Zano.app/Contents/Frameworks/libboost*.dylib
rsync -a ../../../src/gui/qt-daemon/layout/html Zano.app/Contents/MacOS --exclude less --exclude package.json --exclude gulpfile.js
if [ $? -ne 0 ]; then

View file

@ -44,7 +44,7 @@ rmdir build /s /q
mkdir build
cd build
cmake %TESTNET_DEF% -D OPENSSL_ROOT_DIR="%OPENSSL_ROOT_DIR%" -D CMAKE_PREFIX_PATH="%QT_MSVC_PATH%" -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.1" -G "Visual Studio 16 2019" -A x64 -T host=x64 ..
cmake %TESTNET_DEF% -D OPENSSL_ROOT_DIR="%OPENSSL_ROOT_DIR%" -D CMAKE_PREFIX_PATH="%QT_MSVC_PATH%" -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.2" -G "Visual Studio 16 2019" -A x64 -T host=x64 ..
IF %ERRORLEVEL% NEQ 0 (
goto error
)

View file

@ -2,12 +2,12 @@ set -e
function rel_path() # $1 - path to a target dir/file, $2 - base dir
{
python -c "import os.path; print os.path.relpath('$1', os.path.dirname('$2'))"
python3 -c "import os.path; print(os.path.relpath('$1', os.path.dirname('$2')))"
}
function abs_path()
{
python -c "import os.path; print os.path.abspath('$1')"
python3 -c "import os.path; print(os.path.abspath('$1'))"
}
function fix_boost_libs_in_binary() # $1 - path to boost libs, $2 - binary to fix
@ -17,23 +17,24 @@ function fix_boost_libs_in_binary() # $1 - path to boost libs, $2 - binary to fi
echo "fix_boost_libs_in_binary is called with no or invalid parameters"
return 1
fi
install_name_tool -change libboost_system.dylib $1/libboost_system.dylib $2
install_name_tool -change libboost_filesystem.dylib $1/libboost_filesystem.dylib $2
install_name_tool -change libboost_thread.dylib $1/libboost_thread.dylib $2
install_name_tool -change libboost_date_time.dylib $1/libboost_date_time.dylib $2
install_name_tool -change libboost_chrono.dylib $1/libboost_chrono.dylib $2
install_name_tool -change libboost_regex.dylib $1/libboost_regex.dylib $2
install_name_tool -change libboost_serialization.dylib $1/libboost_serialization.dylib $2
install_name_tool -change libboost_atomic.dylib $1/libboost_atomic.dylib $2
install_name_tool -change libboost_program_options.dylib $1/libboost_program_options.dylib $2
install_name_tool -change libboost_locale.dylib $1/libboost_locale.dylib $2
install_name_tool -change libboost_timer.dylib $1/libboost_timer.dylib $2
install_name_tool -change libboost_chrono.dylib $1/libboost_chrono.dylib $2
install_name_tool -change @rpath/libboost_system.dylib $1/libboost_system.dylib $2
install_name_tool -change @rpath/libboost_filesystem.dylib $1/libboost_filesystem.dylib $2
install_name_tool -change @rpath/libboost_thread.dylib $1/libboost_thread.dylib $2
install_name_tool -change @rpath/libboost_date_time.dylib $1/libboost_date_time.dylib $2
install_name_tool -change @rpath/libboost_chrono.dylib $1/libboost_chrono.dylib $2
install_name_tool -change @rpath/libboost_regex.dylib $1/libboost_regex.dylib $2
install_name_tool -change @rpath/libboost_serialization.dylib $1/libboost_serialization.dylib $2
install_name_tool -change @rpath/libboost_atomic.dylib $1/libboost_atomic.dylib $2
install_name_tool -change @rpath/libboost_program_options.dylib $1/libboost_program_options.dylib $2
install_name_tool -change @rpath/libboost_locale.dylib $1/libboost_locale.dylib $2
install_name_tool -change @rpath/libboost_timer.dylib $1/libboost_timer.dylib $2
install_name_tool -change @rpath/libboost_chrono.dylib $1/libboost_chrono.dylib $2
return 0
}
function fix_boost_libs_in_libs() # $1 - path to boost libs, $2 - path to libs folder
{
return 0 # temporary disabled -- 2023-11-20, sowle
install_name_tool -change libboost_system.dylib $1/libboost_system.dylib $2/libboost_filesystem.dylib
install_name_tool -change libboost_system.dylib $1/libboost_system.dylib $2/libboost_thread.dylib
install_name_tool -change libboost_system.dylib $1/libboost_system.dylib $2/libboost_chrono.dylib

View file

@ -0,0 +1,20 @@
{
"jsonrpc": "2.0",
"id": 0,
"method": "transfer",
"params": {
"destinations": [
{
"amount": 1000000000,
"address": "ZxCkEgHf3ci8hgBfboZeCENaYrHBYZ1bLFi5cgWvn4WJLaxfgs4kqG6cJi9ai2zrXWSCpsvRXit14gKjeijx6YPC1zT8rneEf"
}
],
"push_payer": true,
"hide_receiver": false,
"service_entries_permanent": false,
"fee": 1000000000000,
"mixin": 10,
"comment": "",
"service_entries": []
}
}