2019-04-12 06:36:43 +02:00
// Copyright (c) 2014-2019, The Monero Project
2018-04-10 06:49:20 +02:00
// Copyright (c) 2018, The Loki Project
2014-07-23 15:03:52 +02:00
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are
// permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of
// conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
// of conditions and the following disclaimer in the documentation and/or other
// materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
2014-03-03 23:07:58 +01:00
2017-03-01 23:27:27 +01:00
# include <atomic>
2017-11-25 23:25:05 +01:00
# include <boost/algorithm/string.hpp>
2020-07-02 17:50:37 +02:00
# include <limits>
2022-02-10 19:25:55 +01:00
# include <oxenc/hex.h>
2020-06-22 03:42:32 +02:00
# include <variant>
2020-10-23 22:32:28 +02:00
# include "common/hex.h"
2022-05-19 02:44:57 +02:00
# include "cryptonote_core/service_node_list.h"
2020-10-24 00:49:42 +02:00
# include "epee/wipeable_string.h"
# include "epee/string_tools.h"
2018-10-24 02:33:48 +02:00
# include "common/i18n.h"
2020-06-02 05:08:48 +02:00
# include "common/meta.h"
2017-12-22 20:47:12 +01:00
# include "serialization/string.h"
2020-06-02 05:08:48 +02:00
# include "serialization/binary_utils.h"
2014-03-03 23:07:58 +01:00
# include "cryptonote_format_utils.h"
# include "cryptonote_config.h"
# include "crypto/crypto.h"
# include "crypto/hash.h"
2016-06-16 00:37:13 +02:00
# include "ringct/rctSigs.h"
2018-08-15 03:47:45 +02:00
# include "cryptonote_basic/verification_context.h"
2019-05-31 03:06:42 +02:00
# include "cryptonote_core/service_node_voting.h"
2021-01-04 01:09:45 +01:00
# include "cryptonote_core/oxen_name_system.h"
Change logging to easylogging++
This replaces the epee and data_loggers logging systems with
a single one, and also adds filename:line and explicit severity
levels. Categories may be defined, and logging severity set
by category (or set of categories). epee style 0-4 log level
maps to a sensible severity configuration. Log files now also
rotate when reaching 100 MB.
To select which logs to output, use the MONERO_LOGS environment
variable, with a comma separated list of categories (globs are
supported), with their requested severity level after a colon.
If a log matches more than one such setting, the last one in
the configuration string applies. A few examples:
This one is (mostly) silent, only outputting fatal errors:
MONERO_LOGS=*:FATAL
This one is very verbose:
MONERO_LOGS=*:TRACE
This one is totally silent (logwise):
MONERO_LOGS=""
This one outputs all errors and warnings, except for the
"verify" category, which prints just fatal errors (the verify
category is used for logs about incoming transactions and
blocks, and it is expected that some/many will fail to verify,
hence we don't want the spam):
MONERO_LOGS=*:WARNING,verify:FATAL
Log levels are, in decreasing order of priority:
FATAL, ERROR, WARNING, INFO, DEBUG, TRACE
Subcategories may be added using prefixes and globs. This
example will output net.p2p logs at the TRACE level, but all
other net* logs only at INFO:
MONERO_LOGS=*:ERROR,net*:INFO,net.p2p:TRACE
Logs which are intended for the user (which Monero was using
a lot through epee, but really isn't a nice way to go things)
should use the "global" category. There are a few helper macros
for using this category, eg: MGINFO("this shows up by default")
or MGINFO_RED("this is red"), to try to keep a similar look
and feel for now.
Existing epee log macros still exist, and map to the new log
levels, but since they're used as a "user facing" UI element
as much as a logging system, they often don't map well to log
severities (ie, a log level 0 log may be an error, or may be
something we want the user to see, such as an important info).
In those cases, I tried to use the new macros. In other cases,
I left the existing macros in. When modifying logs, it is
probably best to switch to the new macros with explicit levels.
The --log-level options and set_log commands now also accept
category settings, in addition to the epee style log levels.
2017-01-01 17:34:23 +01:00
2017-10-10 16:47:08 +02:00
using namespace crypto ;
2022-09-23 01:27:12 +02:00
# define CHECK_AND_ASSERT_THROW_MES_L1(expr, message) {if(!(expr)) {log::warning(logcat, message); throw std::runtime_error(message);}}
2017-10-21 13:14:31 +02:00
namespace cryptonote
{
2022-09-23 01:27:12 +02:00
static auto logcat = log : : Cat ( " cn " ) ;
2022-09-13 08:57:56 +02:00
2017-10-21 13:14:31 +02:00
static inline unsigned char * operator & ( ec_point & point ) {
return & reinterpret_cast < unsigned char & > ( point ) ;
}
static inline const unsigned char * operator & ( const ec_point & point ) {
return & reinterpret_cast < const unsigned char & > ( point ) ;
}
// a copy of rct::addKeys, since we can't link to libringct to avoid circular dependencies
static void add_public_key ( crypto : : public_key & AB , const crypto : : public_key & A , const crypto : : public_key & B ) {
ge_p3 B2 , A2 ;
CHECK_AND_ASSERT_THROW_MES_L1 ( ge_frombytes_vartime ( & B2 , & B ) = = 0 , " ge_frombytes_vartime failed at " + boost : : lexical_cast < std : : string > ( __LINE__ ) ) ;
CHECK_AND_ASSERT_THROW_MES_L1 ( ge_frombytes_vartime ( & A2 , & A ) = = 0 , " ge_frombytes_vartime failed at " + boost : : lexical_cast < std : : string > ( __LINE__ ) ) ;
ge_cached tmp2 ;
ge_p3_to_cached ( & tmp2 , & B2 ) ;
ge_p1p1 tmp3 ;
ge_add ( & tmp3 , & A2 , & tmp2 ) ;
ge_p1p1_to_p3 ( & A2 , & tmp3 ) ;
ge_p3_tobytes ( & AB , & A2 ) ;
}
2019-10-10 12:45:49 +02:00
uint64_t get_transaction_weight_clawback ( const transaction & tx , size_t n_padded_outputs )
{
const rct : : rctSig & rv = tx . rct_signatures ;
const uint64_t bp_base = 368 ;
const size_t n_outputs = tx . vout . size ( ) ;
if ( n_padded_outputs < = 2 )
return 0 ;
size_t nlr = 0 ;
while ( ( 1u < < nlr ) < n_padded_outputs )
+ + nlr ;
nlr + = 6 ;
const size_t bp_size = 32 * ( 9 + 2 * nlr ) ;
2022-05-16 22:55:05 +02:00
CHECK_AND_ASSERT_THROW_MES_L1 ( n_outputs < = TX_BULLETPROOF_MAX_OUTPUTS , " maximum number of outputs is " + std : : to_string ( TX_BULLETPROOF_MAX_OUTPUTS ) + " per transaction " ) ;
2019-10-10 12:45:49 +02:00
CHECK_AND_ASSERT_THROW_MES_L1 ( bp_base * n_padded_outputs > = bp_size , " Invalid bulletproof clawback: bp_base " + std : : to_string ( bp_base ) + " , n_padded_outputs "
+ std : : to_string ( n_padded_outputs ) + " , bp_size " + std : : to_string ( bp_size ) ) ;
const uint64_t bp_clawback = ( bp_base * n_padded_outputs - bp_size ) * 4 / 5 ;
return bp_clawback ;
}
//---------------------------------------------------------------
2017-10-21 13:14:31 +02:00
}
2014-03-03 23:07:58 +01:00
namespace cryptonote
{
//---------------------------------------------------------------
2020-04-03 22:56:55 +02:00
void get_transaction_prefix_hash ( const transaction_prefix & tx , crypto : : hash & h , hw : : device & hwdev )
{
hwdev . get_transaction_prefix_hash ( tx , h ) ;
}
//---------------------------------------------------------------
crypto : : hash get_transaction_prefix_hash ( const transaction_prefix & tx , hw : : device & hwdev )
{
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
crypto : : hash h { } ;
2020-04-03 22:56:55 +02:00
get_transaction_prefix_hash ( tx , h , hwdev ) ;
return h ;
}
2014-03-03 23:07:58 +01:00
//---------------------------------------------------------------
crypto : : hash get_transaction_prefix_hash ( const transaction_prefix & tx )
{
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
crypto : : hash h { } ;
2014-03-03 23:07:58 +01:00
get_transaction_prefix_hash ( tx , h ) ;
return h ;
}
//---------------------------------------------------------------
2018-05-06 13:00:42 +02:00
bool expand_transaction_1 ( transaction & tx , bool base_only )
{
2019-06-11 20:53:46 +02:00
if ( tx . version > = txversion : : v2_ringct & & ! is_coinbase ( tx ) )
2018-05-06 13:00:42 +02:00
{
rct : : rctSig & rv = tx . rct_signatures ;
2020-11-21 05:20:15 +01:00
if ( rv . type = = rct : : RCTType : : Null )
2020-04-22 18:48:37 +02:00
return true ;
2018-05-06 13:00:42 +02:00
if ( rv . outPk . size ( ) ! = tx . vout . size ( ) )
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " Failed to parse transaction from blob, bad outPk size in tx {} " , get_transaction_hash ( tx ) ) ;
2018-05-06 13:00:42 +02:00
return false ;
}
for ( size_t n = 0 ; n < tx . rct_signatures . outPk . size ( ) ; + + n )
2018-07-24 22:32:49 +02:00
{
2020-06-02 05:47:20 +02:00
if ( ! std : : holds_alternative < txout_to_key > ( tx . vout [ n ] . target ) )
2018-07-24 22:32:49 +02:00
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " Unsupported output type in tx {} " , get_transaction_hash ( tx ) ) ;
2018-07-24 22:32:49 +02:00
return false ;
}
2020-10-16 00:44:36 +02:00
rv . outPk [ n ] . dest = rct : : pk2rct ( var : : get < txout_to_key > ( tx . vout [ n ] . target ) . key ) ;
2018-07-24 22:32:49 +02:00
}
2018-05-06 13:00:42 +02:00
if ( ! base_only )
{
2018-03-30 21:29:42 +02:00
const bool bulletproof = rct : : is_rct_bulletproof ( rv . type ) ;
2018-05-06 13:00:42 +02:00
if ( bulletproof )
{
2018-07-18 23:24:53 +02:00
if ( rv . p . bulletproofs . size ( ) ! = 1 )
2018-05-06 13:00:42 +02:00
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " Failed to parse transaction from blob, bad bulletproofs size in tx {} " , get_transaction_hash ( tx ) ) ;
2018-05-06 13:00:42 +02:00
return false ;
}
2018-07-18 23:24:53 +02:00
if ( rv . p . bulletproofs [ 0 ] . L . size ( ) < 6 )
2018-05-06 13:00:42 +02:00
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " Failed to parse transaction from blob, bad bulletproofs L size in tx {} " , get_transaction_hash ( tx ) ) ;
2018-07-18 23:24:53 +02:00
return false ;
}
const size_t max_outputs = 1 < < ( rv . p . bulletproofs [ 0 ] . L . size ( ) - 6 ) ;
if ( max_outputs < tx . vout . size ( ) )
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " Failed to parse transaction from blob, bad bulletproofs max outputs in tx {} " , get_transaction_hash ( tx ) ) ;
2018-07-18 23:24:53 +02:00
return false ;
2018-05-06 13:00:42 +02:00
}
2018-07-18 23:24:53 +02:00
const size_t n_amounts = tx . vout . size ( ) ;
CHECK_AND_ASSERT_MES ( n_amounts = = rv . outPk . size ( ) , false , " Internal error filling out V " ) ;
rv . p . bulletproofs [ 0 ] . V . resize ( n_amounts ) ;
for ( size_t i = 0 ; i < n_amounts ; + + i )
2018-08-06 13:05:20 +02:00
rv . p . bulletproofs [ 0 ] . V [ i ] = rct : : scalarmultKey ( rv . outPk [ i ] . mask , rct : : INV_EIGHT ) ;
2018-05-06 13:00:42 +02:00
}
}
}
return true ;
}
2020-01-08 02:21:48 +01:00
2020-01-14 00:26:23 +01:00
# if defined(_LIBCPP_VERSION)
2020-01-08 02:21:48 +01:00
# define BINARY_ARCHIVE_STREAM(stream_name, blob) \
std : : stringstream stream_name ; \
stream_name . write ( reinterpret_cast < const char * > ( blob . data ( ) ) , blob . size ( ) )
# else
# define BINARY_ARCHIVE_STREAM(stream_name, blob) \
auto buf = tools : : one_shot_read_buffer { reinterpret_cast < const char * > ( blob . data ( ) ) , blob . size ( ) } ; \
std : : istream stream_name { & buf }
# endif
2018-05-06 13:00:42 +02:00
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool parse_and_validate_tx_from_blob ( const std : : string_view tx_blob , transaction & tx )
2014-03-03 23:07:58 +01:00
{
2020-06-02 05:08:48 +02:00
serialization : : binary_string_unarchiver ba { tx_blob } ;
try {
serialization : : serialize ( ba , tx ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : error ( logcat , " Failed to parse and validate transaction from blob: {} " , e . what ( ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
}
2018-05-06 13:00:42 +02:00
CHECK_AND_ASSERT_MES ( expand_transaction_1 ( tx , false ) , false , " Failed to expand transaction data " ) ;
2017-03-25 10:18:53 +01:00
tx . invalidate_hashes ( ) ;
2018-12-05 21:34:10 +01:00
tx . set_blob_size ( tx_blob . size ( ) ) ;
2014-03-03 23:07:58 +01:00
return true ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool parse_and_validate_tx_base_from_blob ( const std : : string_view tx_blob , transaction & tx )
2017-02-27 21:24:39 +01:00
{
2020-06-02 05:08:48 +02:00
serialization : : binary_string_unarchiver ba { tx_blob } ;
try {
tx . serialize_base ( ba ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : error ( logcat , " Failed to parse transaction base from blob: {} " , e . what ( ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
}
2018-05-06 13:00:42 +02:00
CHECK_AND_ASSERT_MES ( expand_transaction_1 ( tx , true ) , false , " Failed to expand transaction data " ) ;
Pruning
The blockchain prunes seven eighths of prunable tx data.
This saves about two thirds of the blockchain size, while
keeping the node useful as a sync source for an eighth
of the blockchain.
No other data is currently pruned.
There are three ways to prune a blockchain:
- run monerod with --prune-blockchain
- run "prune_blockchain" in the monerod console
- run the monero-blockchain-prune utility
The first two will prune in place. Due to how LMDB works, this
will not reduce the blockchain size on disk. Instead, it will
mark parts of the file as free, so that future data will use
that free space, causing the file to not grow until free space
grows scarce.
The third way will create a second database, a pruned copy of
the original one. Since this is a new file, this one will be
smaller than the original one.
Once the database is pruned, it will stay pruned as it syncs.
That is, there is no need to use --prune-blockchain again, etc.
2018-04-30 00:30:51 +02:00
tx . invalidate_hashes ( ) ;
2017-02-27 21:24:39 +01:00
return true ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool parse_and_validate_tx_prefix_from_blob ( const std : : string_view tx_blob , transaction_prefix & tx )
2018-09-16 20:30:39 +02:00
{
2020-06-02 05:08:48 +02:00
serialization : : binary_string_unarchiver ba { tx_blob } ;
try {
serialization : : value ( ba , tx ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : error ( logcat , " Failed to parse transaction prefix from blob: {} " , e . what ( ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
}
2018-09-16 20:30:39 +02:00
return true ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool parse_and_validate_tx_from_blob ( const std : : string_view tx_blob , transaction & tx , crypto : : hash & tx_hash )
2014-03-03 23:07:58 +01:00
{
2020-06-02 05:08:48 +02:00
serialization : : binary_string_unarchiver ba { tx_blob } ;
try {
serialization : : serialize ( ba , tx ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : error ( logcat , " Failed to parse and validate transaction from blob + hash: {} " , e . what ( ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
}
2018-05-06 13:00:42 +02:00
CHECK_AND_ASSERT_MES ( expand_transaction_1 ( tx , false ) , false , " Failed to expand transaction data " ) ;
2017-03-25 10:18:53 +01:00
tx . invalidate_hashes ( ) ;
2014-03-03 23:07:58 +01:00
//TODO: validate tx
2019-03-19 02:07:10 +01:00
return get_transaction_hash ( tx , tx_hash ) ;
2018-11-13 00:22:20 +01:00
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool parse_and_validate_tx_from_blob ( const std : : string_view tx_blob , transaction & tx , crypto : : hash & tx_hash , crypto : : hash & tx_prefix_hash )
2018-11-13 00:22:20 +01:00
{
if ( ! parse_and_validate_tx_from_blob ( tx_blob , tx , tx_hash ) )
return false ;
2014-03-03 23:07:58 +01:00
get_transaction_prefix_hash ( tx , tx_prefix_hash ) ;
return true ;
}
2018-02-10 11:38:33 +01:00
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool is_v1_tx ( const std : : string_view tx_blob )
Pruning
The blockchain prunes seven eighths of prunable tx data.
This saves about two thirds of the blockchain size, while
keeping the node useful as a sync source for an eighth
of the blockchain.
No other data is currently pruned.
There are three ways to prune a blockchain:
- run monerod with --prune-blockchain
- run "prune_blockchain" in the monerod console
- run the monero-blockchain-prune utility
The first two will prune in place. Due to how LMDB works, this
will not reduce the blockchain size on disk. Instead, it will
mark parts of the file as free, so that future data will use
that free space, causing the file to not grow until free space
grows scarce.
The third way will create a second database, a pruned copy of
the original one. Since this is a new file, this one will be
smaller than the original one.
Once the database is pruned, it will stay pruned as it syncs.
That is, there is no need to use --prune-blockchain again, etc.
2018-04-30 00:30:51 +02:00
{
uint64_t version ;
2020-06-02 05:08:48 +02:00
if ( tools : : read_varint ( tx_blob , version ) < = 0 )
Pruning
The blockchain prunes seven eighths of prunable tx data.
This saves about two thirds of the blockchain size, while
keeping the node useful as a sync source for an eighth
of the blockchain.
No other data is currently pruned.
There are three ways to prune a blockchain:
- run monerod with --prune-blockchain
- run "prune_blockchain" in the monerod console
- run the monero-blockchain-prune utility
The first two will prune in place. Due to how LMDB works, this
will not reduce the blockchain size on disk. Instead, it will
mark parts of the file as free, so that future data will use
that free space, causing the file to not grow until free space
grows scarce.
The third way will create a second database, a pruned copy of
the original one. Since this is a new file, this one will be
smaller than the original one.
Once the database is pruned, it will stay pruned as it syncs.
That is, there is no need to use --prune-blockchain again, etc.
2018-04-30 00:30:51 +02:00
throw std : : runtime_error ( " Internal error getting transaction version " ) ;
return version < = 1 ;
}
//---------------------------------------------------------------
2018-02-20 17:01:27 +01:00
bool generate_key_image_helper ( const account_keys & ack , const std : : unordered_map < crypto : : public_key , subaddress_index > & subaddresses , const crypto : : public_key & out_key , const crypto : : public_key & tx_public_key , const std : : vector < crypto : : public_key > & additional_tx_public_keys , size_t real_output_index , keypair & in_ephemeral , crypto : : key_image & ki , hw : : device & hwdev )
2014-03-03 23:07:58 +01:00
{
2019-10-31 23:26:58 +01:00
crypto : : key_derivation recv_derivation { } ;
2018-03-05 08:16:30 +01:00
bool r = hwdev . generate_key_derivation ( tx_public_key , ack . m_view_secret_key , recv_derivation ) ;
2018-08-24 11:50:34 +02:00
if ( ! r )
{
2022-10-08 04:30:29 +02:00
log : : warning ( logcat , " key image helper: failed to generate_key_derivation({}, <{}>) " , tx_public_key , tools : : type_to_hex ( ack . m_view_secret_key ) ) ;
2018-08-24 11:50:34 +02:00
memcpy ( & recv_derivation , rct : : identity ( ) . bytes , sizeof ( recv_derivation ) ) ;
}
2014-03-03 23:07:58 +01:00
2017-02-19 03:42:10 +01:00
std : : vector < crypto : : key_derivation > additional_recv_derivations ;
for ( size_t i = 0 ; i < additional_tx_public_keys . size ( ) ; + + i )
{
2019-10-31 23:26:58 +01:00
crypto : : key_derivation additional_recv_derivation { } ;
2018-03-05 08:16:30 +01:00
r = hwdev . generate_key_derivation ( additional_tx_public_keys [ i ] , ack . m_view_secret_key , additional_recv_derivation ) ;
2018-08-24 11:50:34 +02:00
if ( ! r )
{
2022-10-08 04:30:29 +02:00
log : : warning ( logcat , " key image helper: failed to generate_key_derivation({}, {}) " , additional_tx_public_keys [ i ] , tools : : type_to_hex ( ack . m_view_secret_key ) ) ;
2018-08-24 11:50:34 +02:00
}
else
{
additional_recv_derivations . push_back ( additional_recv_derivation ) ;
}
2017-02-19 03:42:10 +01:00
}
2020-06-02 00:30:19 +02:00
std : : optional < subaddress_receive_info > subaddr_recv_info = is_out_to_acc_precomp ( subaddresses , out_key , recv_derivation , additional_recv_derivations , real_output_index , hwdev ) ;
2017-02-19 03:42:10 +01:00
CHECK_AND_ASSERT_MES ( subaddr_recv_info , false , " key image helper: given output pubkey doesn't seem to belong to this address " ) ;
2018-02-20 17:01:27 +01:00
return generate_key_image_helper_precomp ( ack , out_key , subaddr_recv_info - > derivation , real_output_index , subaddr_recv_info - > index , in_ephemeral , ki , hwdev ) ;
2017-02-19 03:42:10 +01:00
}
//---------------------------------------------------------------
2018-02-20 17:01:27 +01:00
bool generate_key_image_helper_precomp ( const account_keys & ack , const crypto : : public_key & out_key , const crypto : : key_derivation & recv_derivation , size_t real_output_index , const subaddress_index & received_index , keypair & in_ephemeral , crypto : : key_image & ki , hw : : device & hwdev )
2017-02-19 03:42:10 +01:00
{
2023-01-16 21:52:30 +01:00
// This tries to compute the key image using a hardware device, if this succeeds return immediately, otherwise continue
2019-02-23 15:28:18 +01:00
if ( hwdev . compute_key_image ( ack , out_key , recv_derivation , real_output_index , received_index , in_ephemeral , ki ) )
{
return true ;
}
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
if ( ! ack . m_spend_secret_key )
2017-02-19 03:42:10 +01:00
{
// for watch-only wallet, simply copy the known output pubkey
in_ephemeral . pub = out_key ;
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
in_ephemeral . sec . zero ( ) ;
2017-02-19 03:42:10 +01:00
}
else
{
// derive secret key with subaddress - step 1: original CN derivation
crypto : : secret_key scalar_step1 ;
2018-03-05 08:16:30 +01:00
hwdev . derive_secret_key ( recv_derivation , real_output_index , ack . m_spend_secret_key , scalar_step1 ) ; // computes Hs(a*R || idx) + b
2017-02-19 03:42:10 +01:00
// step 2: add Hs(a || index_major || index_minor)
2017-10-21 13:14:31 +02:00
crypto : : secret_key subaddr_sk ;
2017-02-19 03:42:10 +01:00
crypto : : secret_key scalar_step2 ;
if ( received_index . is_zero ( ) )
{
scalar_step2 = scalar_step1 ; // treat index=(0,0) as a special case representing the main address
}
else
{
2018-03-05 06:24:48 +01:00
subaddr_sk = hwdev . get_subaddress_secret_key ( ack . m_view_secret_key , received_index ) ;
2018-02-20 17:01:27 +01:00
hwdev . sc_secret_add ( scalar_step2 , scalar_step1 , subaddr_sk ) ;
2017-02-19 03:42:10 +01:00
}
2014-03-03 23:07:58 +01:00
2017-02-19 03:42:10 +01:00
in_ephemeral . sec = scalar_step2 ;
2017-10-21 13:14:31 +02:00
if ( ack . m_multisig_keys . empty ( ) )
{
// when not in multisig, we know the full spend secret key, so the output pubkey can be obtained by scalarmultBase
2018-03-05 08:16:30 +01:00
CHECK_AND_ASSERT_MES ( hwdev . secret_key_to_public_key ( in_ephemeral . sec , in_ephemeral . pub ) , false , " Failed to derive public key " ) ;
2017-10-21 13:14:31 +02:00
}
else
{
// when in multisig, we only know the partial spend secret key. but we do know the full spend public key, so the output pubkey can be obtained by using the standard CN key derivation
2018-03-05 08:16:30 +01:00
CHECK_AND_ASSERT_MES ( hwdev . derive_public_key ( recv_derivation , real_output_index , ack . m_account_address . m_spend_public_key , in_ephemeral . pub ) , false , " Failed to derive public key " ) ;
2017-10-21 13:14:31 +02:00
// and don't forget to add the contribution from the subaddress part
if ( ! received_index . is_zero ( ) )
{
crypto : : public_key subaddr_pk ;
2018-03-05 08:16:30 +01:00
CHECK_AND_ASSERT_MES ( hwdev . secret_key_to_public_key ( subaddr_sk , subaddr_pk ) , false , " Failed to derive public key " ) ;
2017-10-21 13:14:31 +02:00
add_public_key ( in_ephemeral . pub , in_ephemeral . pub , subaddr_pk ) ;
}
}
CHECK_AND_ASSERT_MES ( in_ephemeral . pub = = out_key ,
false , " key image helper precomp: given output pubkey doesn't match the derived one " ) ;
2017-02-19 03:42:10 +01:00
}
2014-03-03 23:07:58 +01:00
2018-03-05 08:16:30 +01:00
hwdev . generate_key_image ( in_ephemeral . pub , in_ephemeral . sec , ki ) ;
2014-03-03 23:07:58 +01:00
return true ;
}
//---------------------------------------------------------------
2022-04-15 22:24:48 +02:00
std : : optional < uint64_t > parse_amount ( std : : string_view str_amount )
2014-03-03 23:07:58 +01:00
{
2022-04-15 22:24:48 +02:00
uint64_t amount ;
2020-06-23 21:50:20 +02:00
tools : : trim ( str_amount ) ;
2014-03-03 23:07:58 +01:00
2020-06-23 21:50:20 +02:00
auto parts = tools : : split ( str_amount , " . " sv ) ;
if ( parts . size ( ) > 2 )
2022-04-15 22:24:48 +02:00
return std : : nullopt ; // 123.456.789 no thanks.
2020-06-23 21:50:20 +02:00
if ( parts . size ( ) = = 2 & & parts [ 1 ] . empty ( ) )
parts . pop_back ( ) ; // allow "123." (treat it as as "123")
if ( parts [ 0 ] . find_first_not_of ( " 0123456789 " sv ) ! = std : : string : : npos )
2022-04-15 22:24:48 +02:00
return std : : nullopt ; // whole part contains non-digit
2020-06-23 21:50:20 +02:00
if ( parts [ 0 ] . empty ( ) ) {
// Only allow an empty whole number part if there is a fractional part.
if ( parts . size ( ) = = 1 )
2022-04-15 22:24:48 +02:00
return std : : nullopt ;
2020-06-23 21:50:20 +02:00
amount = 0 ;
2014-03-03 23:07:58 +01:00
}
2014-04-02 18:00:17 +02:00
else
{
2020-06-23 21:50:20 +02:00
if ( ! tools : : parse_int ( parts [ 0 ] , amount ) )
2022-04-15 22:24:48 +02:00
return std : : nullopt ;
2020-06-23 21:50:20 +02:00
// Scale up the number (e.g. 12 from "12.45") to atomic units.
2022-05-16 22:55:05 +02:00
if ( amount > std : : numeric_limits < uint64_t > : : max ( ) / oxen : : COIN )
2022-04-15 22:24:48 +02:00
return std : : nullopt ; // would overflow
2022-05-16 22:55:05 +02:00
amount * = oxen : : COIN ;
2014-04-02 18:00:17 +02:00
}
2020-06-23 21:50:20 +02:00
if ( parts . size ( ) = = 1 )
2022-04-15 22:24:48 +02:00
return amount ;
2020-06-23 21:50:20 +02:00
if ( parts [ 1 ] . find_first_not_of ( " 0123456789 " sv ) ! = std : : string : : npos )
2022-04-15 22:24:48 +02:00
return std : : nullopt ; // fractional part contains non-digit
2020-06-23 21:50:20 +02:00
// If too long, but with insignificant 0's, trim them off
2022-05-16 22:55:05 +02:00
while ( parts [ 1 ] . size ( ) > oxen : : DISPLAY_DECIMAL_POINT & & parts [ 1 ] . back ( ) = = ' 0 ' )
2020-06-23 21:50:20 +02:00
parts [ 1 ] . remove_suffix ( 1 ) ;
2022-05-16 22:55:05 +02:00
if ( parts [ 1 ] . size ( ) > oxen : : DISPLAY_DECIMAL_POINT )
2022-04-15 22:24:48 +02:00
return std : : nullopt ; // fractional part has too many significant digits
2020-06-23 21:50:20 +02:00
uint64_t fractional ;
if ( ! tools : : parse_int ( parts [ 1 ] , fractional ) )
2022-04-15 22:24:48 +02:00
return std : : nullopt ;
2014-04-02 18:00:17 +02:00
2020-06-23 21:50:20 +02:00
// Scale up the value if it wasn't a full fractional value, e.g. if we have "10.45" then we
// need to convert the 45 we just parsed to 450'000'000.
2022-05-16 22:55:05 +02:00
for ( size_t i = parts [ 1 ] . size ( ) ; i < oxen : : DISPLAY_DECIMAL_POINT ; i + + )
2020-06-23 21:50:20 +02:00
fractional * = 10 ;
2014-04-02 18:00:17 +02:00
2020-06-23 21:50:20 +02:00
if ( fractional > std : : numeric_limits < uint64_t > : : max ( ) - amount )
2022-04-15 22:24:48 +02:00
return std : : nullopt ; // would overflow
2020-06-23 21:50:20 +02:00
amount + = fractional ;
2022-04-15 22:24:48 +02:00
return amount ;
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
2018-07-18 23:24:53 +02:00
uint64_t get_transaction_weight ( const transaction & tx , size_t blob_size )
{
2019-10-10 12:45:49 +02:00
CHECK_AND_ASSERT_MES ( ! tx . pruned , std : : numeric_limits < uint64_t > : : max ( ) , " get_transaction_weight does not support pruned txes " ) ;
2019-06-11 20:53:46 +02:00
if ( tx . version < txversion : : v2_ringct )
2018-07-18 23:24:53 +02:00
return blob_size ;
const rct : : rctSig & rv = tx . rct_signatures ;
if ( ! rct : : is_rct_bulletproof ( rv . type ) )
return blob_size ;
const size_t n_padded_outputs = rct : : n_bulletproof_max_amounts ( rv . p . bulletproofs ) ;
2019-10-10 12:45:49 +02:00
uint64_t bp_clawback = get_transaction_weight_clawback ( tx , n_padded_outputs ) ;
2018-07-18 23:24:53 +02:00
CHECK_AND_ASSERT_THROW_MES_L1 ( bp_clawback < = std : : numeric_limits < uint64_t > : : max ( ) - blob_size , " Weight overflow " ) ;
return blob_size + bp_clawback ;
}
//---------------------------------------------------------------
2019-10-10 12:45:49 +02:00
uint64_t get_pruned_transaction_weight ( const transaction & tx )
{
CHECK_AND_ASSERT_MES ( tx . pruned , std : : numeric_limits < uint64_t > : : max ( ) , " get_pruned_transaction_weight does not support non pruned txes " ) ;
2020-05-25 05:58:56 +02:00
CHECK_AND_ASSERT_MES ( tx . version > = txversion : : v2_ringct , std : : numeric_limits < uint64_t > : : max ( ) , " get_pruned_transaction_weight does not support v1 txes " ) ;
2020-11-21 05:20:15 +01:00
CHECK_AND_ASSERT_MES ( tx . rct_signatures . type > = rct : : RCTType : : Bulletproof2 ,
2019-10-10 12:45:49 +02:00
std : : numeric_limits < uint64_t > : : max ( ) , " get_pruned_transaction_weight does not support older range proof types " ) ;
CHECK_AND_ASSERT_MES ( ! tx . vin . empty ( ) , std : : numeric_limits < uint64_t > : : max ( ) , " empty vin " ) ;
2020-06-22 03:42:32 +02:00
CHECK_AND_ASSERT_MES ( std : : holds_alternative < cryptonote : : txin_to_key > ( tx . vin [ 0 ] ) , std : : numeric_limits < uint64_t > : : max ( ) , " empty vin " ) ;
2019-10-10 12:45:49 +02:00
// get pruned data size
2020-06-22 03:38:09 +02:00
uint64_t weight = serialization : : dump_binary ( const_cast < transaction & > ( tx ) ) . size ( ) ;
2019-10-10 12:45:49 +02:00
// nbps (technically varint)
weight + = 1 ;
// calculate deterministic bulletproofs size (assumes canonical BP format)
size_t nrl = 0 , n_padded_outputs ;
while ( ( n_padded_outputs = ( 1u < < nrl ) ) < tx . vout . size ( ) )
+ + nrl ;
nrl + = 6 ;
2020-06-22 03:38:09 +02:00
uint64_t extra = 32 * ( 9 + 2 * nrl ) + 2 ;
2019-10-10 12:45:49 +02:00
weight + = extra ;
2019-06-09 15:02:16 +02:00
// calculate deterministic CLSAG/MLSAG data size
2020-10-16 00:44:36 +02:00
const size_t ring_size = var : : get < cryptonote : : txin_to_key > ( tx . vin [ 0 ] ) . key_offsets . size ( ) ;
2020-11-21 05:20:15 +01:00
if ( tx . rct_signatures . type = = rct : : RCTType : : CLSAG )
2019-06-09 15:02:16 +02:00
extra = tx . vin . size ( ) * ( ring_size + 2 ) * 32 ;
else
extra = tx . vin . size ( ) * ( ring_size * ( 1 + 1 ) * 32 + 32 /* cc */ ) ;
2019-10-10 12:45:49 +02:00
weight + = extra ;
// calculate deterministic pseudoOuts size
extra = 32 * ( tx . vin . size ( ) ) ;
weight + = extra ;
// clawback
uint64_t bp_clawback = get_transaction_weight_clawback ( tx , n_padded_outputs ) ;
CHECK_AND_ASSERT_THROW_MES_L1 ( bp_clawback < = std : : numeric_limits < uint64_t > : : max ( ) - weight , " Weight overflow " ) ;
weight + = bp_clawback ;
return weight ;
}
//---------------------------------------------------------------
2018-07-18 23:24:53 +02:00
uint64_t get_transaction_weight ( const transaction & tx )
{
2020-06-02 05:08:48 +02:00
size_t blob_size =
tx . is_blob_size_valid ( )
? tx . blob_size
: serialization : : dump_binary ( const_cast < transaction & > ( tx ) ) . size ( ) ;
2018-11-29 23:01:48 +01:00
return get_transaction_weight ( tx , blob_size ) ;
2018-07-18 23:24:53 +02:00
}
//---------------------------------------------------------------
Generic burn fee checking + blink burn fee checking
This adds the ability for check_fee() to also check the burn amount.
This requires passing extra info through `add_tx()` (and the various
things that call it), so I took the:
bool keeped_by_block, bool relayed, bool do_not_relay
argument triplet, moved it into a struct in tx_pool.h, then added the other fee
options there (along with some static factory functions for generating the
typical sets of option).
The majority of this commit is chasing that change through the codebase and
test suite.
This is used by blink but should also help LNS and other future burn
transactions to verify a burn amount simply when adding the transation to the
mempool. It supports a fixed burn amount, a burn amount as a multiple of the
minimum tx fee, and also allows you to increase the minimum tx fee (so that,
for example, we could require blink txes to pay miners 250% of the usual
minimum (unimportant) priority tx fee.
- Removed a useless core::add_new_tx() overload that wasn't used anywhere.
Blink-specific changes:
(I'd normally separate these into a separate commit, but they got interwoven
fairly heavily with the above change).
- changed the way blink burning is specified so that we have three knobs for
fee adjustment (fixed burn fee; base fee multiple; and required miner tx fee).
The fixed amount is currently 0, base fee is 400%, and require miner tx fee is
simply 100% (i.e. no different than a normal transaction). This is the same as
before this commit, but is changing how they are being specified in
cryptonote_config.h.
- blink tx fee, burn amount, and miner tx fee (if > 100%) now get checked
before signing a blink tx. (These fee checks don't apply to anyone else --
when propagating over the network only the miner tx fee is checked).
- Added a couple of checks for blink quorums: 1) make sure they have reached
the blink hf; 2) make sure the submitted tx version conforms to the current hf
min/max tx version.
- print blink fee information in simplewallet's `fee` output
- add "typical" fee calculations in the `fee` output:
[wallet T6SCwL (has locked stakes)]: fee
Current fee is 0.000000850 loki per byte + 0.020000000 loki per output
No backlog at priority 1
No backlog at priority 2
No backlog at priority 3
No backlog at priority 4
Current blink fee is 0.000004250 loki per byte + 0.100000000 loki per output
Estimated typical small transaction fees: 0.042125000 (unimportant), 0.210625000 (normal), 1.053125000 (elevated), 5.265625000 (priority), 0.210625000 (blink)
where "small" here is the same tx size (2500 bytes + 2 outputs) used to
estimate backlogs.
2019-11-09 04:14:15 +01:00
bool get_tx_miner_fee ( const transaction & tx , uint64_t & fee , bool burning_enabled , uint64_t * burned )
2014-03-03 23:07:58 +01:00
{
Generic burn fee checking + blink burn fee checking
This adds the ability for check_fee() to also check the burn amount.
This requires passing extra info through `add_tx()` (and the various
things that call it), so I took the:
bool keeped_by_block, bool relayed, bool do_not_relay
argument triplet, moved it into a struct in tx_pool.h, then added the other fee
options there (along with some static factory functions for generating the
typical sets of option).
The majority of this commit is chasing that change through the codebase and
test suite.
This is used by blink but should also help LNS and other future burn
transactions to verify a burn amount simply when adding the transation to the
mempool. It supports a fixed burn amount, a burn amount as a multiple of the
minimum tx fee, and also allows you to increase the minimum tx fee (so that,
for example, we could require blink txes to pay miners 250% of the usual
minimum (unimportant) priority tx fee.
- Removed a useless core::add_new_tx() overload that wasn't used anywhere.
Blink-specific changes:
(I'd normally separate these into a separate commit, but they got interwoven
fairly heavily with the above change).
- changed the way blink burning is specified so that we have three knobs for
fee adjustment (fixed burn fee; base fee multiple; and required miner tx fee).
The fixed amount is currently 0, base fee is 400%, and require miner tx fee is
simply 100% (i.e. no different than a normal transaction). This is the same as
before this commit, but is changing how they are being specified in
cryptonote_config.h.
- blink tx fee, burn amount, and miner tx fee (if > 100%) now get checked
before signing a blink tx. (These fee checks don't apply to anyone else --
when propagating over the network only the miner tx fee is checked).
- Added a couple of checks for blink quorums: 1) make sure they have reached
the blink hf; 2) make sure the submitted tx version conforms to the current hf
min/max tx version.
- print blink fee information in simplewallet's `fee` output
- add "typical" fee calculations in the `fee` output:
[wallet T6SCwL (has locked stakes)]: fee
Current fee is 0.000000850 loki per byte + 0.020000000 loki per output
No backlog at priority 1
No backlog at priority 2
No backlog at priority 3
No backlog at priority 4
Current blink fee is 0.000004250 loki per byte + 0.100000000 loki per output
Estimated typical small transaction fees: 0.042125000 (unimportant), 0.210625000 (normal), 1.053125000 (elevated), 5.265625000 (priority), 0.210625000 (blink)
where "small" here is the same tx size (2500 bytes + 2 outputs) used to
estimate backlogs.
2019-11-09 04:14:15 +01:00
if ( burned )
* burned = 0 ;
2019-06-11 20:53:46 +02:00
if ( tx . version > = txversion : : v2_ringct )
2016-06-16 00:37:13 +02:00
{
fee = tx . rct_signatures . txnFee ;
2019-10-30 22:28:47 +01:00
if ( burning_enabled )
Generic burn fee checking + blink burn fee checking
This adds the ability for check_fee() to also check the burn amount.
This requires passing extra info through `add_tx()` (and the various
things that call it), so I took the:
bool keeped_by_block, bool relayed, bool do_not_relay
argument triplet, moved it into a struct in tx_pool.h, then added the other fee
options there (along with some static factory functions for generating the
typical sets of option).
The majority of this commit is chasing that change through the codebase and
test suite.
This is used by blink but should also help LNS and other future burn
transactions to verify a burn amount simply when adding the transation to the
mempool. It supports a fixed burn amount, a burn amount as a multiple of the
minimum tx fee, and also allows you to increase the minimum tx fee (so that,
for example, we could require blink txes to pay miners 250% of the usual
minimum (unimportant) priority tx fee.
- Removed a useless core::add_new_tx() overload that wasn't used anywhere.
Blink-specific changes:
(I'd normally separate these into a separate commit, but they got interwoven
fairly heavily with the above change).
- changed the way blink burning is specified so that we have three knobs for
fee adjustment (fixed burn fee; base fee multiple; and required miner tx fee).
The fixed amount is currently 0, base fee is 400%, and require miner tx fee is
simply 100% (i.e. no different than a normal transaction). This is the same as
before this commit, but is changing how they are being specified in
cryptonote_config.h.
- blink tx fee, burn amount, and miner tx fee (if > 100%) now get checked
before signing a blink tx. (These fee checks don't apply to anyone else --
when propagating over the network only the miner tx fee is checked).
- Added a couple of checks for blink quorums: 1) make sure they have reached
the blink hf; 2) make sure the submitted tx version conforms to the current hf
min/max tx version.
- print blink fee information in simplewallet's `fee` output
- add "typical" fee calculations in the `fee` output:
[wallet T6SCwL (has locked stakes)]: fee
Current fee is 0.000000850 loki per byte + 0.020000000 loki per output
No backlog at priority 1
No backlog at priority 2
No backlog at priority 3
No backlog at priority 4
Current blink fee is 0.000004250 loki per byte + 0.100000000 loki per output
Estimated typical small transaction fees: 0.042125000 (unimportant), 0.210625000 (normal), 1.053125000 (elevated), 5.265625000 (priority), 0.210625000 (blink)
where "small" here is the same tx size (2500 bytes + 2 outputs) used to
estimate backlogs.
2019-11-09 04:14:15 +01:00
{
uint64_t fee_burned = get_burned_amount_from_tx_extra ( tx . extra ) ;
fee - = std : : min ( fee , fee_burned ) ;
if ( burned )
* burned = fee_burned ;
}
2016-06-16 00:37:13 +02:00
return true ;
}
2019-10-30 22:19:46 +01:00
uint64_t amount_in ;
if ( ! get_inputs_money_amount ( tx , amount_in ) ) return false ;
uint64_t amount_out = get_outs_money_amount ( tx ) ;
2014-03-03 23:07:58 +01:00
CHECK_AND_ASSERT_MES ( amount_in > = amount_out , false , " transaction spend ( " < < amount_in < < " ) more than it has ( " < < amount_out < < " ) " ) ;
fee = amount_in - amount_out ;
return true ;
}
//---------------------------------------------------------------
2019-10-30 22:28:47 +01:00
uint64_t get_tx_miner_fee ( const transaction & tx , bool burning_enabled )
2014-03-03 23:07:58 +01:00
{
uint64_t r = 0 ;
2019-10-30 22:28:47 +01:00
if ( ! get_tx_miner_fee ( tx , r , burning_enabled ) )
2014-03-03 23:07:58 +01:00
return 0 ;
return r ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
[[nodiscard]] bool parse_tx_extra ( const std : : vector < uint8_t > & tx_extra , std : : vector < tx_extra_field > & tx_extra_fields )
2014-03-03 23:07:58 +01:00
{
2014-05-03 18:19:43 +02:00
tx_extra_fields . clear ( ) ;
if ( tx_extra . empty ( ) )
return true ;
2020-06-02 05:08:48 +02:00
serialization : : binary_string_unarchiver ar { tx_extra } ;
2014-05-03 18:19:43 +02:00
2020-06-02 05:08:48 +02:00
try {
serialization : : deserialize_all ( ar , tx_extra_fields ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : warning ( logcat , " {}: failed to deserialize extra field: {}; extra = {} " , __func__ , e . what ( ) , oxenc : : to_hex ( tx_extra . begin ( ) , tx_extra . end ( ) ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
2014-03-03 23:07:58 +01:00
}
2014-05-03 18:19:43 +02:00
2014-03-03 23:07:58 +01:00
return true ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
[[nodiscard]] bool sort_tx_extra ( const std : : vector < uint8_t > & tx_extra , std : : vector < uint8_t > & sorted_tx_extra )
2018-08-03 12:21:08 +02:00
{
std : : vector < tx_extra_field > tx_extra_fields ;
2020-06-02 05:08:48 +02:00
if ( ! parse_tx_extra ( tx_extra , tx_extra_fields ) )
return false ;
2018-08-03 12:21:08 +02:00
2020-06-02 05:08:48 +02:00
// Sort according to the order of variant alternatives in the variant itself
std : : stable_sort ( tx_extra_fields . begin ( ) , tx_extra_fields . end ( ) , [ ] ( auto & a , auto & b ) { return a . index ( ) < b . index ( ) ; } ) ;
2018-08-03 12:21:08 +02:00
2020-06-02 05:08:48 +02:00
serialization : : binary_string_archiver ar ;
try {
for ( auto & f : tx_extra_fields )
serialization : : value ( ar , f ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " failed to serialize tx extra field: {} " , e . what ( ) ) ;
2018-08-03 12:21:08 +02:00
return false ;
}
2020-06-02 05:08:48 +02:00
std : : string extrastr = ar . str ( ) ;
sorted_tx_extra = std : : vector < uint8_t > ( extrastr . begin ( ) , extrastr . end ( ) ) ;
2018-08-03 12:21:08 +02:00
return true ;
}
//---------------------------------------------------------------
2016-12-09 19:21:21 +01:00
crypto : : public_key get_tx_pub_key_from_extra ( const std : : vector < uint8_t > & tx_extra , size_t pk_index )
2014-05-03 18:19:43 +02:00
{
tx_extra_pub_key pub_key_field ;
2020-06-02 06:21:05 +02:00
if ( get_field_from_tx_extra ( tx_extra , pub_key_field , pk_index ) )
return pub_key_field . pub_key ;
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
return null < public_key > ;
2014-05-03 18:19:43 +02:00
}
//---------------------------------------------------------------
2016-12-09 19:21:21 +01:00
crypto : : public_key get_tx_pub_key_from_extra ( const transaction_prefix & tx_prefix , size_t pk_index )
2016-08-06 20:19:25 +02:00
{
2016-12-09 19:21:21 +01:00
return get_tx_pub_key_from_extra ( tx_prefix . extra , pk_index ) ;
2016-08-06 20:19:25 +02:00
}
//---------------------------------------------------------------
2020-06-02 06:21:05 +02:00
void add_tagged_data_to_tx_extra ( std : : vector < uint8_t > & tx_extra , uint8_t tag , std : : string_view data )
2017-08-04 19:05:35 +02:00
{
2020-06-02 06:21:05 +02:00
tx_extra . reserve ( tx_extra . size ( ) + 1 + data . size ( ) ) ;
tx_extra . push_back ( tag ) ;
tx_extra . insert ( tx_extra . end ( ) , data . begin ( ) , data . end ( ) ) ;
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
2017-02-19 03:42:10 +01:00
std : : vector < crypto : : public_key > get_additional_tx_pub_keys_from_extra ( const std : : vector < uint8_t > & tx_extra )
{
tx_extra_additional_pub_keys additional_pub_keys ;
2020-06-02 06:21:05 +02:00
if ( get_field_from_tx_extra ( tx_extra , additional_pub_keys ) )
return additional_pub_keys . data ;
return { } ;
2017-02-19 03:42:10 +01:00
}
//---------------------------------------------------------------
std : : vector < crypto : : public_key > get_additional_tx_pub_keys_from_extra ( const transaction_prefix & tx )
{
return get_additional_tx_pub_keys_from_extra ( tx . extra ) ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
static bool add_tx_extra_field_to_tx_extra ( std : : vector < uint8_t > & tx_extra , tx_extra_field & field )
2017-02-19 03:42:10 +01:00
{
2020-06-02 05:08:48 +02:00
std : : string tx_extra_str ;
try {
tx_extra_str = serialization : : dump_binary ( field ) ;
} catch ( . . . ) {
2019-01-25 04:15:52 +01:00
return false ;
2020-06-02 05:08:48 +02:00
}
2019-01-25 04:15:52 +01:00
2020-06-02 05:08:48 +02:00
tx_extra . reserve ( tx_extra . size ( ) + tx_extra_str . size ( ) ) ;
tx_extra . insert ( tx_extra . end ( ) , tx_extra_str . begin ( ) , tx_extra_str . end ( ) ) ;
2019-01-25 04:15:52 +01:00
return true ;
}
//---------------------------------------------------------------
bool add_additional_tx_pub_keys_to_extra ( std : : vector < uint8_t > & tx_extra , const std : : vector < crypto : : public_key > & additional_pub_keys )
{
tx_extra_field field = tx_extra_additional_pub_keys { additional_pub_keys } ;
2022-09-13 08:57:56 +02:00
if ( ! add_tx_extra_field_to_tx_extra ( tx_extra , field ) )
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " failed to serialize tx extra additional tx pub keys " ) ;
2022-09-13 08:57:56 +02:00
return false ;
}
2017-02-19 03:42:10 +01:00
return true ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
bool add_extra_nonce_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const std : : string & extra_nonce )
2014-03-03 23:07:58 +01:00
{
2014-05-03 18:19:43 +02:00
CHECK_AND_ASSERT_MES ( extra_nonce . size ( ) < = TX_EXTRA_NONCE_MAX_COUNT , false , " extra nonce could be 255 bytes max " ) ;
2020-06-02 05:08:48 +02:00
tx_extra . reserve ( tx_extra . size ( ) + 2 + extra_nonce . size ( ) ) ;
tx_extra . push_back ( TX_EXTRA_NONCE ) ; // write tag
tx_extra . push_back ( static_cast < uint8_t > ( extra_nonce . size ( ) ) ) ; // write len
std : : copy ( extra_nonce . begin ( ) , extra_nonce . end ( ) , std : : back_inserter ( tx_extra ) ) ;
2014-05-03 18:19:43 +02:00
return true ;
}
Service Node Deregister Part 5 (#89)
* Retrieve quorum list from height, reviewed
* Setup data structures for de/register TX
* Submit and validate partial/full deregisters
* Add P2P relaying of partial deregistration votes
* Code review adjustments for deregistration part 1
- Fix check_tx_semantic
- Remove signature_pod as votes are now stored as blobs. Serialization
overrides don't intefere with crypto::signature anymore.
* deregistration_vote_pool - changed sign/verify interface and removed repeated code
* Misc review, fix sign/verify api, vote threshold
* Deregister/tx edge case handling for combinatoric votes
* core, service_node_list: separated address from service node pubkey
* Retrieve quorum list from height, reviewed
* Setup data structures for de/register TX
* Submit and validate partial/full deregisters
* Add P2P relaying of partial deregistration votes
* Code review adjustments for deregistration part 1
- Fix check_tx_semantic
- Remove signature_pod as votes are now stored as blobs. Serialization
overrides don't intefere with crypto::signature anymore.
* deregistration_vote_pool - changed sign/verify interface and removed repeated code
* Misc review, fix sign/verify api, vote threshold
* Deregister/tx edge case handling for combinatoric votes
* Store service node lists for the duration of deregister lifetimes
* Quorum min/max bug, sort node list, fix node to test list
* Change quorum to store acc pub address, fix oob bug
* Code review for expiring votes, acc keys to pub_key, improve err msgs
* Add early out for is_deregistration_tx and protect against quorum changes
* Remove debug code, fix segfault
* Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states
Incorrect assumption that a transaction can be kept in the chain if it could
eventually become invalid, because if it were the chain would be split and
eventually these transaction would be dropped. But also that we should not
override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
2022-05-16 22:55:05 +02:00
bool add_service_node_state_change_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const tx_extra_service_node_state_change & state_change , const hf hf_version )
Relax deregistration rules
The replaces the deregistration mechanism with a new state change
mechanism (beginning at the v12 fork) which can change a service node's
network status via three potential values (and is extensible in the
future to handle more):
- deregistered -- this is the same as the existing deregistration; the
SN is instantly removed from the SN list.
- decommissioned -- this is a sort of temporary deregistration: your SN
remains in the service node list, but is removed from the rewards list
and from any network duties.
- recommissioned -- this tx is sent by a quorum if they observe a
decommissioned SN sending uptime proofs again. Upon reception, the SN
is reactivated and put on the end of the reward list.
Since this is broadening the quorum use, this also renames the relevant
quorum to a "obligations" quorum (since it validates SN obligations),
while the transactions are "state_change" transactions (since they
change the state of a registered SN).
The new parameters added to service_node_rules.h control how this works:
// Service node decommissioning: as service nodes stay up they earn "credits" (measured in blocks)
// towards a future outage. A new service node starts out with INITIAL_CREDIT, and then builds up
// CREDIT_PER_DAY for each day the service node remains active up to a maximum of
// DECOMMISSION_MAX_CREDIT.
//
// If a service node stops sending uptime proofs, a quorum will consider whether the service node
// has built up enough credits (at least MINIMUM): if so, instead of submitting a deregistration,
// it instead submits a decommission. This removes the service node from the list of active
// service nodes both for rewards and for any active network duties. If the service node comes
// back online (i.e. starts sending the required performance proofs again) before the credits run
// out then a quorum will reinstate the service node using a recommission transaction, which adds
// the service node back to the bottom of the service node reward list, and resets its accumulated
// credits to 0. If it does not come back online within the required number of blocks (i.e. the
// accumulated credit at the point of decommissioning) then a quorum will send a permanent
// deregistration transaction to the network, starting a 30-day deregistration count down.
This commit currently includes values (which are not necessarily
finalized):
- 8 hours (240 blocks) of credit required for activation of a
decommission (rather than a deregister)
- 0 initial credits at registration
- a maximum of 24 hours (720 blocks) of credits
- credits accumulate at a rate that you hit 24 hours of credits after 30
days of operation.
Miscellaneous other details of this PR:
- a new TX extra tag is used for the state change (including
deregistrations). The old extra tag has no version or type tag, so
couldn't be reused. The data in the new tag is slightly more
efficiently packed than the old deregistration transaction, so it gets
used for deregistrations (starting at the v12 fork) as well.
- Correct validator/worker selection required generalizing the shuffle
function to be able to shuffle just part of a vector. This lets us
stick any down service nodes at the end of the potential list, then
select validators by only shuffling the part of the index vector that
contains active service indices. Once the validators are selected, the
remainder of the list (this time including decommissioned SN indices) is
shuffled to select quorum workers to check, thus allowing decommisioned
nodes to be randomly included in the nodes to check without being
selected as a validator.
- Swarm recalculation was not quite right: swarms were recalculated on
SN registrations, even if those registrations were include shared node
registrations, but *not* recalculated on stakes. Starting with the
upgrade this behaviour is fixed (swarms aren't actually used currently
and aren't consensus-relevant so recalculating early won't hurt
anything).
- Details on decomm/dereg are added to RPC info and print_sn/print_sn_status
- Slightly improves the % of reward output in the print_sn output by
rounding it to two digits, and reserves space in the output string to
avoid excessive reallocations.
- Adds various debugging at higher debug levels to quorum voting (into
all of voting itself, vote transmission, and vote reception).
- Reset service node list internal data structure version to 0. The SN
list has to be rescanned anyway at upgrade (its size has changed), so we
might as well reset the version and remove the version-dependent
serialization code. (Note that the affected code here is for SN states
in lmdb storage, not for SN-to-SN communication serialization).
2019-06-18 23:57:02 +02:00
{
tx_extra_field field ;
2022-05-16 22:55:05 +02:00
if ( hf_version < hf : : hf12_checkpointing )
Relax deregistration rules
The replaces the deregistration mechanism with a new state change
mechanism (beginning at the v12 fork) which can change a service node's
network status via three potential values (and is extensible in the
future to handle more):
- deregistered -- this is the same as the existing deregistration; the
SN is instantly removed from the SN list.
- decommissioned -- this is a sort of temporary deregistration: your SN
remains in the service node list, but is removed from the rewards list
and from any network duties.
- recommissioned -- this tx is sent by a quorum if they observe a
decommissioned SN sending uptime proofs again. Upon reception, the SN
is reactivated and put on the end of the reward list.
Since this is broadening the quorum use, this also renames the relevant
quorum to a "obligations" quorum (since it validates SN obligations),
while the transactions are "state_change" transactions (since they
change the state of a registered SN).
The new parameters added to service_node_rules.h control how this works:
// Service node decommissioning: as service nodes stay up they earn "credits" (measured in blocks)
// towards a future outage. A new service node starts out with INITIAL_CREDIT, and then builds up
// CREDIT_PER_DAY for each day the service node remains active up to a maximum of
// DECOMMISSION_MAX_CREDIT.
//
// If a service node stops sending uptime proofs, a quorum will consider whether the service node
// has built up enough credits (at least MINIMUM): if so, instead of submitting a deregistration,
// it instead submits a decommission. This removes the service node from the list of active
// service nodes both for rewards and for any active network duties. If the service node comes
// back online (i.e. starts sending the required performance proofs again) before the credits run
// out then a quorum will reinstate the service node using a recommission transaction, which adds
// the service node back to the bottom of the service node reward list, and resets its accumulated
// credits to 0. If it does not come back online within the required number of blocks (i.e. the
// accumulated credit at the point of decommissioning) then a quorum will send a permanent
// deregistration transaction to the network, starting a 30-day deregistration count down.
This commit currently includes values (which are not necessarily
finalized):
- 8 hours (240 blocks) of credit required for activation of a
decommission (rather than a deregister)
- 0 initial credits at registration
- a maximum of 24 hours (720 blocks) of credits
- credits accumulate at a rate that you hit 24 hours of credits after 30
days of operation.
Miscellaneous other details of this PR:
- a new TX extra tag is used for the state change (including
deregistrations). The old extra tag has no version or type tag, so
couldn't be reused. The data in the new tag is slightly more
efficiently packed than the old deregistration transaction, so it gets
used for deregistrations (starting at the v12 fork) as well.
- Correct validator/worker selection required generalizing the shuffle
function to be able to shuffle just part of a vector. This lets us
stick any down service nodes at the end of the potential list, then
select validators by only shuffling the part of the index vector that
contains active service indices. Once the validators are selected, the
remainder of the list (this time including decommissioned SN indices) is
shuffled to select quorum workers to check, thus allowing decommisioned
nodes to be randomly included in the nodes to check without being
selected as a validator.
- Swarm recalculation was not quite right: swarms were recalculated on
SN registrations, even if those registrations were include shared node
registrations, but *not* recalculated on stakes. Starting with the
upgrade this behaviour is fixed (swarms aren't actually used currently
and aren't consensus-relevant so recalculating early won't hurt
anything).
- Details on decomm/dereg are added to RPC info and print_sn/print_sn_status
- Slightly improves the % of reward output in the print_sn output by
rounding it to two digits, and reserves space in the output string to
avoid excessive reallocations.
- Adds various debugging at higher debug levels to quorum voting (into
all of voting itself, vote transmission, and vote reception).
- Reset service node list internal data structure version to 0. The SN
list has to be rescanned anyway at upgrade (its size has changed), so we
might as well reset the version and remove the version-dependent
serialization code. (Note that the affected code here is for SN states
in lmdb storage, not for SN-to-SN communication serialization).
2019-06-18 23:57:02 +02:00
{
CHECK_AND_ASSERT_MES ( state_change . state = = service_nodes : : new_state : : deregister , false , " internal error: cannot construct an old deregistration for a non-deregistration state change (before hardfork v12) " ) ;
field = tx_extra_service_node_deregister_old { state_change } ;
}
else
{
field = state_change ;
}
Service Node Deregister Part 5 (#89)
* Retrieve quorum list from height, reviewed
* Setup data structures for de/register TX
* Submit and validate partial/full deregisters
* Add P2P relaying of partial deregistration votes
* Code review adjustments for deregistration part 1
- Fix check_tx_semantic
- Remove signature_pod as votes are now stored as blobs. Serialization
overrides don't intefere with crypto::signature anymore.
* deregistration_vote_pool - changed sign/verify interface and removed repeated code
* Misc review, fix sign/verify api, vote threshold
* Deregister/tx edge case handling for combinatoric votes
* core, service_node_list: separated address from service node pubkey
* Retrieve quorum list from height, reviewed
* Setup data structures for de/register TX
* Submit and validate partial/full deregisters
* Add P2P relaying of partial deregistration votes
* Code review adjustments for deregistration part 1
- Fix check_tx_semantic
- Remove signature_pod as votes are now stored as blobs. Serialization
overrides don't intefere with crypto::signature anymore.
* deregistration_vote_pool - changed sign/verify interface and removed repeated code
* Misc review, fix sign/verify api, vote threshold
* Deregister/tx edge case handling for combinatoric votes
* Store service node lists for the duration of deregister lifetimes
* Quorum min/max bug, sort node list, fix node to test list
* Change quorum to store acc pub address, fix oob bug
* Code review for expiring votes, acc keys to pub_key, improve err msgs
* Add early out for is_deregistration_tx and protect against quorum changes
* Remove debug code, fix segfault
* Remove irrelevant check for tx v3 in blockchain, fix >= height for pruning quorum states
Incorrect assumption that a transaction can be kept in the chain if it could
eventually become invalid, because if it were the chain would be split and
eventually these transaction would be dropped. But also that we should not
override the pre-existing logic which handles this case anyway.
2018-07-18 04:42:47 +02:00
Relax deregistration rules
The replaces the deregistration mechanism with a new state change
mechanism (beginning at the v12 fork) which can change a service node's
network status via three potential values (and is extensible in the
future to handle more):
- deregistered -- this is the same as the existing deregistration; the
SN is instantly removed from the SN list.
- decommissioned -- this is a sort of temporary deregistration: your SN
remains in the service node list, but is removed from the rewards list
and from any network duties.
- recommissioned -- this tx is sent by a quorum if they observe a
decommissioned SN sending uptime proofs again. Upon reception, the SN
is reactivated and put on the end of the reward list.
Since this is broadening the quorum use, this also renames the relevant
quorum to a "obligations" quorum (since it validates SN obligations),
while the transactions are "state_change" transactions (since they
change the state of a registered SN).
The new parameters added to service_node_rules.h control how this works:
// Service node decommissioning: as service nodes stay up they earn "credits" (measured in blocks)
// towards a future outage. A new service node starts out with INITIAL_CREDIT, and then builds up
// CREDIT_PER_DAY for each day the service node remains active up to a maximum of
// DECOMMISSION_MAX_CREDIT.
//
// If a service node stops sending uptime proofs, a quorum will consider whether the service node
// has built up enough credits (at least MINIMUM): if so, instead of submitting a deregistration,
// it instead submits a decommission. This removes the service node from the list of active
// service nodes both for rewards and for any active network duties. If the service node comes
// back online (i.e. starts sending the required performance proofs again) before the credits run
// out then a quorum will reinstate the service node using a recommission transaction, which adds
// the service node back to the bottom of the service node reward list, and resets its accumulated
// credits to 0. If it does not come back online within the required number of blocks (i.e. the
// accumulated credit at the point of decommissioning) then a quorum will send a permanent
// deregistration transaction to the network, starting a 30-day deregistration count down.
This commit currently includes values (which are not necessarily
finalized):
- 8 hours (240 blocks) of credit required for activation of a
decommission (rather than a deregister)
- 0 initial credits at registration
- a maximum of 24 hours (720 blocks) of credits
- credits accumulate at a rate that you hit 24 hours of credits after 30
days of operation.
Miscellaneous other details of this PR:
- a new TX extra tag is used for the state change (including
deregistrations). The old extra tag has no version or type tag, so
couldn't be reused. The data in the new tag is slightly more
efficiently packed than the old deregistration transaction, so it gets
used for deregistrations (starting at the v12 fork) as well.
- Correct validator/worker selection required generalizing the shuffle
function to be able to shuffle just part of a vector. This lets us
stick any down service nodes at the end of the potential list, then
select validators by only shuffling the part of the index vector that
contains active service indices. Once the validators are selected, the
remainder of the list (this time including decommissioned SN indices) is
shuffled to select quorum workers to check, thus allowing decommisioned
nodes to be randomly included in the nodes to check without being
selected as a validator.
- Swarm recalculation was not quite right: swarms were recalculated on
SN registrations, even if those registrations were include shared node
registrations, but *not* recalculated on stakes. Starting with the
upgrade this behaviour is fixed (swarms aren't actually used currently
and aren't consensus-relevant so recalculating early won't hurt
anything).
- Details on decomm/dereg are added to RPC info and print_sn/print_sn_status
- Slightly improves the % of reward output in the print_sn output by
rounding it to two digits, and reserves space in the output string to
avoid excessive reallocations.
- Adds various debugging at higher debug levels to quorum voting (into
all of voting itself, vote transmission, and vote reception).
- Reset service node list internal data structure version to 0. The SN
list has to be rescanned anyway at upgrade (its size has changed), so we
might as well reset the version and remove the version-dependent
serialization code. (Note that the affected code here is for SN states
in lmdb storage, not for SN-to-SN communication serialization).
2019-06-18 23:57:02 +02:00
bool r = add_tx_extra_field_to_tx_extra ( tx_extra , field ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to serialize tx extra service node state change " ) ;
2018-06-29 06:47:00 +02:00
return true ;
}
Relax deregistration rules
The replaces the deregistration mechanism with a new state change
mechanism (beginning at the v12 fork) which can change a service node's
network status via three potential values (and is extensible in the
future to handle more):
- deregistered -- this is the same as the existing deregistration; the
SN is instantly removed from the SN list.
- decommissioned -- this is a sort of temporary deregistration: your SN
remains in the service node list, but is removed from the rewards list
and from any network duties.
- recommissioned -- this tx is sent by a quorum if they observe a
decommissioned SN sending uptime proofs again. Upon reception, the SN
is reactivated and put on the end of the reward list.
Since this is broadening the quorum use, this also renames the relevant
quorum to a "obligations" quorum (since it validates SN obligations),
while the transactions are "state_change" transactions (since they
change the state of a registered SN).
The new parameters added to service_node_rules.h control how this works:
// Service node decommissioning: as service nodes stay up they earn "credits" (measured in blocks)
// towards a future outage. A new service node starts out with INITIAL_CREDIT, and then builds up
// CREDIT_PER_DAY for each day the service node remains active up to a maximum of
// DECOMMISSION_MAX_CREDIT.
//
// If a service node stops sending uptime proofs, a quorum will consider whether the service node
// has built up enough credits (at least MINIMUM): if so, instead of submitting a deregistration,
// it instead submits a decommission. This removes the service node from the list of active
// service nodes both for rewards and for any active network duties. If the service node comes
// back online (i.e. starts sending the required performance proofs again) before the credits run
// out then a quorum will reinstate the service node using a recommission transaction, which adds
// the service node back to the bottom of the service node reward list, and resets its accumulated
// credits to 0. If it does not come back online within the required number of blocks (i.e. the
// accumulated credit at the point of decommissioning) then a quorum will send a permanent
// deregistration transaction to the network, starting a 30-day deregistration count down.
This commit currently includes values (which are not necessarily
finalized):
- 8 hours (240 blocks) of credit required for activation of a
decommission (rather than a deregister)
- 0 initial credits at registration
- a maximum of 24 hours (720 blocks) of credits
- credits accumulate at a rate that you hit 24 hours of credits after 30
days of operation.
Miscellaneous other details of this PR:
- a new TX extra tag is used for the state change (including
deregistrations). The old extra tag has no version or type tag, so
couldn't be reused. The data in the new tag is slightly more
efficiently packed than the old deregistration transaction, so it gets
used for deregistrations (starting at the v12 fork) as well.
- Correct validator/worker selection required generalizing the shuffle
function to be able to shuffle just part of a vector. This lets us
stick any down service nodes at the end of the potential list, then
select validators by only shuffling the part of the index vector that
contains active service indices. Once the validators are selected, the
remainder of the list (this time including decommissioned SN indices) is
shuffled to select quorum workers to check, thus allowing decommisioned
nodes to be randomly included in the nodes to check without being
selected as a validator.
- Swarm recalculation was not quite right: swarms were recalculated on
SN registrations, even if those registrations were include shared node
registrations, but *not* recalculated on stakes. Starting with the
upgrade this behaviour is fixed (swarms aren't actually used currently
and aren't consensus-relevant so recalculating early won't hurt
anything).
- Details on decomm/dereg are added to RPC info and print_sn/print_sn_status
- Slightly improves the % of reward output in the print_sn output by
rounding it to two digits, and reserves space in the output string to
avoid excessive reallocations.
- Adds various debugging at higher debug levels to quorum voting (into
all of voting itself, vote transmission, and vote reception).
- Reset service node list internal data structure version to 0. The SN
list has to be rescanned anyway at upgrade (its size has changed), so we
might as well reset the version and remove the version-dependent
serialization code. (Note that the affected code here is for SN states
in lmdb storage, not for SN-to-SN communication serialization).
2019-06-18 23:57:02 +02:00
2018-06-29 06:47:00 +02:00
//---------------------------------------------------------------
2018-07-28 08:27:04 +02:00
void add_service_node_pubkey_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const crypto : : public_key & pubkey )
{
2020-06-02 06:21:05 +02:00
add_tx_extra < tx_extra_service_node_pubkey > ( tx_extra , pubkey ) ;
2018-07-28 08:27:04 +02:00
}
//---------------------------------------------------------------
bool get_service_node_pubkey_from_tx_extra ( const std : : vector < uint8_t > & tx_extra , crypto : : public_key & pubkey )
{
2020-06-02 06:21:05 +02:00
tx_extra_service_node_pubkey pk ;
if ( ! get_field_from_tx_extra ( tx_extra , pk ) )
2018-07-28 08:27:04 +02:00
return false ;
2020-06-02 06:21:05 +02:00
pubkey = pk . m_service_node_key ;
2018-07-28 08:27:04 +02:00
return true ;
}
//---------------------------------------------------------------
void add_service_node_contributor_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const cryptonote : : account_public_address & address )
{
2020-06-02 06:21:05 +02:00
add_tx_extra < tx_extra_service_node_contributor > ( tx_extra , address ) ;
2018-07-28 08:27:04 +02:00
}
//---------------------------------------------------------------
2018-08-03 10:34:49 +02:00
bool get_tx_secret_key_from_tx_extra ( const std : : vector < uint8_t > & tx_extra , crypto : : secret_key & key )
{
tx_extra_tx_secret_key seckey ;
2020-06-02 06:21:05 +02:00
if ( ! get_field_from_tx_extra ( tx_extra , seckey ) )
2018-08-03 10:34:49 +02:00
return false ;
key = seckey . key ;
return true ;
}
//---------------------------------------------------------------
void add_tx_secret_key_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const crypto : : secret_key & key )
{
2020-06-02 06:21:05 +02:00
add_tx_extra < tx_extra_tx_secret_key > ( tx_extra , key ) ;
2019-01-25 04:15:52 +01:00
}
//---------------------------------------------------------------
bool add_tx_key_image_proofs_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const tx_extra_tx_key_image_proofs & proofs )
{
tx_extra_field field = proofs ;
2022-09-13 08:57:56 +02:00
if ( ! add_tx_extra_field_to_tx_extra ( tx_extra , field ) )
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " failed to serialize tx extra tx key image proof " ) ;
2022-09-13 08:57:56 +02:00
return false ;
}
return true ;
2019-01-25 04:15:52 +01:00
}
//---------------------------------------------------------------
bool add_tx_key_image_unlock_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const tx_extra_tx_key_image_unlock & unlock )
{
tx_extra_field field = unlock ;
2022-09-13 08:57:56 +02:00
if ( ! add_tx_extra_field_to_tx_extra ( tx_extra , field ) )
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " failed to serialize tx extra tx key image unlock " ) ;
2022-09-13 08:57:56 +02:00
return false ;
}
return true ;
2019-01-25 04:15:52 +01:00
}
//---------------------------------------------------------------
2018-07-28 08:27:04 +02:00
bool get_service_node_contributor_from_tx_extra ( const std : : vector < uint8_t > & tx_extra , cryptonote : : account_public_address & address )
{
tx_extra_service_node_contributor contributor ;
2020-06-02 06:21:05 +02:00
if ( ! get_field_from_tx_extra ( tx_extra , contributor ) )
2018-07-28 08:27:04 +02:00
return false ;
address . m_spend_public_key = contributor . m_spend_public_key ;
address . m_view_public_key = contributor . m_view_public_key ;
return true ;
}
//---------------------------------------------------------------
2022-05-19 02:44:57 +02:00
bool add_service_node_registration_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const service_nodes : : registration_details & reg )
2018-07-18 08:51:26 +02:00
{
2022-05-19 02:44:57 +02:00
tx_extra_field field ;
auto & txreg = field . emplace < tx_extra_service_node_register > ( ) ;
txreg . amounts . reserve ( reg . reserved . size ( ) ) ;
txreg . public_spend_keys . reserve ( reg . reserved . size ( ) ) ;
txreg . public_view_keys . reserve ( reg . reserved . size ( ) ) ;
for ( const auto & [ addr , amount ] : reg . reserved )
2018-07-18 08:51:26 +02:00
{
2022-05-19 02:44:57 +02:00
txreg . public_spend_keys . push_back ( addr . m_spend_public_key ) ;
txreg . public_view_keys . push_back ( addr . m_view_public_key ) ;
txreg . amounts . push_back ( amount ) ;
2018-07-18 08:51:26 +02:00
}
2022-05-19 02:44:57 +02:00
txreg . fee = reg . fee ;
txreg . hf_or_expiration = reg . hf ;
txreg . signature = reg . signature ;
2019-01-25 04:15:52 +01:00
2022-09-13 08:57:56 +02:00
if ( ! add_tx_extra_field_to_tx_extra ( tx_extra , field ) )
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " failed to serialize tx extra registration tx " ) ;
2022-09-13 08:57:56 +02:00
return false ;
}
2018-07-18 08:51:26 +02:00
return true ;
}
//---------------------------------------------------------------
void add_service_node_winner_to_tx_extra ( std : : vector < uint8_t > & tx_extra , const crypto : : public_key & winner )
{
2020-06-02 06:21:05 +02:00
add_tx_extra < tx_extra_service_node_winner > ( tx_extra , winner ) ;
2018-06-29 06:47:00 +02:00
}
//---------------------------------------------------------------
2022-05-16 22:55:05 +02:00
bool get_service_node_state_change_from_tx_extra ( const std : : vector < uint8_t > & tx_extra , tx_extra_service_node_state_change & state_change , const hf hf_version )
2018-07-12 04:07:34 +02:00
{
2022-05-16 22:55:05 +02:00
if ( hf_version > = hf : : hf12_checkpointing ) {
Relax deregistration rules
The replaces the deregistration mechanism with a new state change
mechanism (beginning at the v12 fork) which can change a service node's
network status via three potential values (and is extensible in the
future to handle more):
- deregistered -- this is the same as the existing deregistration; the
SN is instantly removed from the SN list.
- decommissioned -- this is a sort of temporary deregistration: your SN
remains in the service node list, but is removed from the rewards list
and from any network duties.
- recommissioned -- this tx is sent by a quorum if they observe a
decommissioned SN sending uptime proofs again. Upon reception, the SN
is reactivated and put on the end of the reward list.
Since this is broadening the quorum use, this also renames the relevant
quorum to a "obligations" quorum (since it validates SN obligations),
while the transactions are "state_change" transactions (since they
change the state of a registered SN).
The new parameters added to service_node_rules.h control how this works:
// Service node decommissioning: as service nodes stay up they earn "credits" (measured in blocks)
// towards a future outage. A new service node starts out with INITIAL_CREDIT, and then builds up
// CREDIT_PER_DAY for each day the service node remains active up to a maximum of
// DECOMMISSION_MAX_CREDIT.
//
// If a service node stops sending uptime proofs, a quorum will consider whether the service node
// has built up enough credits (at least MINIMUM): if so, instead of submitting a deregistration,
// it instead submits a decommission. This removes the service node from the list of active
// service nodes both for rewards and for any active network duties. If the service node comes
// back online (i.e. starts sending the required performance proofs again) before the credits run
// out then a quorum will reinstate the service node using a recommission transaction, which adds
// the service node back to the bottom of the service node reward list, and resets its accumulated
// credits to 0. If it does not come back online within the required number of blocks (i.e. the
// accumulated credit at the point of decommissioning) then a quorum will send a permanent
// deregistration transaction to the network, starting a 30-day deregistration count down.
This commit currently includes values (which are not necessarily
finalized):
- 8 hours (240 blocks) of credit required for activation of a
decommission (rather than a deregister)
- 0 initial credits at registration
- a maximum of 24 hours (720 blocks) of credits
- credits accumulate at a rate that you hit 24 hours of credits after 30
days of operation.
Miscellaneous other details of this PR:
- a new TX extra tag is used for the state change (including
deregistrations). The old extra tag has no version or type tag, so
couldn't be reused. The data in the new tag is slightly more
efficiently packed than the old deregistration transaction, so it gets
used for deregistrations (starting at the v12 fork) as well.
- Correct validator/worker selection required generalizing the shuffle
function to be able to shuffle just part of a vector. This lets us
stick any down service nodes at the end of the potential list, then
select validators by only shuffling the part of the index vector that
contains active service indices. Once the validators are selected, the
remainder of the list (this time including decommissioned SN indices) is
shuffled to select quorum workers to check, thus allowing decommisioned
nodes to be randomly included in the nodes to check without being
selected as a validator.
- Swarm recalculation was not quite right: swarms were recalculated on
SN registrations, even if those registrations were include shared node
registrations, but *not* recalculated on stakes. Starting with the
upgrade this behaviour is fixed (swarms aren't actually used currently
and aren't consensus-relevant so recalculating early won't hurt
anything).
- Details on decomm/dereg are added to RPC info and print_sn/print_sn_status
- Slightly improves the % of reward output in the print_sn output by
rounding it to two digits, and reserves space in the output string to
avoid excessive reallocations.
- Adds various debugging at higher debug levels to quorum voting (into
all of voting itself, vote transmission, and vote reception).
- Reset service node list internal data structure version to 0. The SN
list has to be rescanned anyway at upgrade (its size has changed), so we
might as well reset the version and remove the version-dependent
serialization code. (Note that the affected code here is for SN states
in lmdb storage, not for SN-to-SN communication serialization).
2019-06-18 23:57:02 +02:00
// Look for a new-style state change field:
2020-06-02 06:21:05 +02:00
return get_field_from_tx_extra ( tx_extra , state_change ) ;
Relax deregistration rules
The replaces the deregistration mechanism with a new state change
mechanism (beginning at the v12 fork) which can change a service node's
network status via three potential values (and is extensible in the
future to handle more):
- deregistered -- this is the same as the existing deregistration; the
SN is instantly removed from the SN list.
- decommissioned -- this is a sort of temporary deregistration: your SN
remains in the service node list, but is removed from the rewards list
and from any network duties.
- recommissioned -- this tx is sent by a quorum if they observe a
decommissioned SN sending uptime proofs again. Upon reception, the SN
is reactivated and put on the end of the reward list.
Since this is broadening the quorum use, this also renames the relevant
quorum to a "obligations" quorum (since it validates SN obligations),
while the transactions are "state_change" transactions (since they
change the state of a registered SN).
The new parameters added to service_node_rules.h control how this works:
// Service node decommissioning: as service nodes stay up they earn "credits" (measured in blocks)
// towards a future outage. A new service node starts out with INITIAL_CREDIT, and then builds up
// CREDIT_PER_DAY for each day the service node remains active up to a maximum of
// DECOMMISSION_MAX_CREDIT.
//
// If a service node stops sending uptime proofs, a quorum will consider whether the service node
// has built up enough credits (at least MINIMUM): if so, instead of submitting a deregistration,
// it instead submits a decommission. This removes the service node from the list of active
// service nodes both for rewards and for any active network duties. If the service node comes
// back online (i.e. starts sending the required performance proofs again) before the credits run
// out then a quorum will reinstate the service node using a recommission transaction, which adds
// the service node back to the bottom of the service node reward list, and resets its accumulated
// credits to 0. If it does not come back online within the required number of blocks (i.e. the
// accumulated credit at the point of decommissioning) then a quorum will send a permanent
// deregistration transaction to the network, starting a 30-day deregistration count down.
This commit currently includes values (which are not necessarily
finalized):
- 8 hours (240 blocks) of credit required for activation of a
decommission (rather than a deregister)
- 0 initial credits at registration
- a maximum of 24 hours (720 blocks) of credits
- credits accumulate at a rate that you hit 24 hours of credits after 30
days of operation.
Miscellaneous other details of this PR:
- a new TX extra tag is used for the state change (including
deregistrations). The old extra tag has no version or type tag, so
couldn't be reused. The data in the new tag is slightly more
efficiently packed than the old deregistration transaction, so it gets
used for deregistrations (starting at the v12 fork) as well.
- Correct validator/worker selection required generalizing the shuffle
function to be able to shuffle just part of a vector. This lets us
stick any down service nodes at the end of the potential list, then
select validators by only shuffling the part of the index vector that
contains active service indices. Once the validators are selected, the
remainder of the list (this time including decommissioned SN indices) is
shuffled to select quorum workers to check, thus allowing decommisioned
nodes to be randomly included in the nodes to check without being
selected as a validator.
- Swarm recalculation was not quite right: swarms were recalculated on
SN registrations, even if those registrations were include shared node
registrations, but *not* recalculated on stakes. Starting with the
upgrade this behaviour is fixed (swarms aren't actually used currently
and aren't consensus-relevant so recalculating early won't hurt
anything).
- Details on decomm/dereg are added to RPC info and print_sn/print_sn_status
- Slightly improves the % of reward output in the print_sn output by
rounding it to two digits, and reserves space in the output string to
avoid excessive reallocations.
- Adds various debugging at higher debug levels to quorum voting (into
all of voting itself, vote transmission, and vote reception).
- Reset service node list internal data structure version to 0. The SN
list has to be rescanned anyway at upgrade (its size has changed), so we
might as well reset the version and remove the version-dependent
serialization code. (Note that the affected code here is for SN states
in lmdb storage, not for SN-to-SN communication serialization).
2019-06-18 23:57:02 +02:00
}
2020-06-02 06:21:05 +02:00
// v11 or earlier; parse the old style and copy into a new style
tx_extra_service_node_deregister_old dereg ;
if ( ! get_field_from_tx_extra ( tx_extra , dereg ) )
return false ;
state_change = tx_extra_service_node_state_change {
2021-03-24 18:43:01 +01:00
tx_extra_service_node_state_change : : version_t : : v0 ,
service_nodes : : new_state : : deregister , dereg . block_height , dereg . service_node_index , 0 , 0 , { dereg . votes . begin ( ) , dereg . votes . end ( ) } } ;
2020-06-02 06:21:05 +02:00
return true ;
2018-07-12 04:07:34 +02:00
}
//---------------------------------------------------------------
2018-07-18 08:51:26 +02:00
crypto : : public_key get_service_node_winner_from_tx_extra ( const std : : vector < uint8_t > & tx_extra )
{
// find corresponding field
tx_extra_service_node_winner winner ;
2020-06-02 06:21:05 +02:00
if ( get_field_from_tx_extra ( tx_extra , winner ) )
return winner . m_service_node_key ;
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
return null < public_key > ;
2019-11-01 01:58:48 +01:00
}
//---------------------------------------------------------------
2021-01-04 01:09:45 +01:00
void add_oxen_name_system_to_tx_extra ( std : : vector < uint8_t > & tx_extra , tx_extra_oxen_name_system const & entry )
2019-11-01 01:58:48 +01:00
{
tx_extra_field field = entry ;
add_tx_extra_field_to_tx_extra ( tx_extra , field ) ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool remove_field_from_tx_extra ( std : : vector < uint8_t > & tx_extra , const size_t variant_index )
2015-08-03 22:15:10 +02:00
{
2017-01-07 17:05:02 +01:00
if ( tx_extra . empty ( ) )
return true ;
2015-08-03 22:15:10 +02:00
2020-06-02 05:08:48 +02:00
serialization : : binary_string_unarchiver ar { tx_extra } ;
serialization : : binary_string_archiver newar ;
try {
do
{
tx_extra_field field ;
value ( ar , field ) ;
if ( field . index ( ) ! = variant_index )
value ( newar , field ) ;
} while ( ar . remaining_bytes ( ) > 0 ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " {}: failed to deserialize extra field: {}; extra = {} " , __func__ , e . what ( ) , oxenc : : to_hex ( tx_extra . begin ( ) , tx_extra . end ( ) ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
2015-08-03 22:15:10 +02:00
}
2020-06-02 05:08:48 +02:00
std : : string s = newar . str ( ) ;
2015-08-03 22:15:10 +02:00
tx_extra . clear ( ) ;
tx_extra . reserve ( s . size ( ) ) ;
std : : copy ( s . begin ( ) , s . end ( ) , std : : back_inserter ( tx_extra ) ) ;
return true ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
void set_payment_id_to_tx_extra_nonce ( std : : string & extra_nonce , const crypto : : hash & payment_id )
2014-05-03 18:19:43 +02:00
{
extra_nonce . clear ( ) ;
2015-08-09 11:09:39 +02:00
extra_nonce . push_back ( TX_EXTRA_NONCE_PAYMENT_ID ) ;
2014-05-03 18:19:43 +02:00
const uint8_t * payment_id_ptr = reinterpret_cast < const uint8_t * > ( & payment_id ) ;
std : : copy ( payment_id_ptr , payment_id_ptr + sizeof ( payment_id ) , std : : back_inserter ( extra_nonce ) ) ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
void set_encrypted_payment_id_to_tx_extra_nonce ( std : : string & extra_nonce , const crypto : : hash8 & payment_id )
2015-08-09 11:09:39 +02:00
{
extra_nonce . clear ( ) ;
extra_nonce . push_back ( TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID ) ;
const uint8_t * payment_id_ptr = reinterpret_cast < const uint8_t * > ( & payment_id ) ;
std : : copy ( payment_id_ptr , payment_id_ptr + sizeof ( payment_id ) , std : : back_inserter ( extra_nonce ) ) ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
bool get_payment_id_from_tx_extra_nonce ( const std : : string & extra_nonce , crypto : : hash & payment_id )
2014-05-03 18:19:43 +02:00
{
if ( sizeof ( crypto : : hash ) + 1 ! = extra_nonce . size ( ) )
return false ;
2015-08-09 11:09:39 +02:00
if ( TX_EXTRA_NONCE_PAYMENT_ID ! = extra_nonce [ 0 ] )
2014-05-03 18:19:43 +02:00
return false ;
payment_id = * reinterpret_cast < const crypto : : hash * > ( extra_nonce . data ( ) + 1 ) ;
2015-08-03 22:15:10 +02:00
return true ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
bool get_encrypted_payment_id_from_tx_extra_nonce ( const std : : string & extra_nonce , crypto : : hash8 & payment_id )
2015-08-09 11:09:39 +02:00
{
if ( sizeof ( crypto : : hash8 ) + 1 ! = extra_nonce . size ( ) )
return false ;
if ( TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID ! = extra_nonce [ 0 ] )
return false ;
payment_id = * reinterpret_cast < const crypto : : hash8 * > ( extra_nonce . data ( ) + 1 ) ;
return true ;
}
//---------------------------------------------------------------
2019-10-30 22:28:47 +01:00
uint64_t get_burned_amount_from_tx_extra ( const std : : vector < uint8_t > & tx_extra )
{
tx_extra_burn burn ;
2020-06-02 06:21:05 +02:00
if ( get_field_from_tx_extra ( tx_extra , burn ) )
2019-10-30 22:28:47 +01:00
return burn . amount ;
return 0 ;
}
//---------------------------------------------------------------
bool add_burned_amount_to_tx_extra ( std : : vector < uint8_t > & tx_extra , uint64_t burn )
{
tx_extra_field field = tx_extra_burn { burn } ;
2022-09-13 08:57:56 +02:00
if ( ! add_tx_extra_field_to_tx_extra ( tx_extra , field ) )
{
2022-09-23 01:27:12 +02:00
log : : info ( logcat , " failed to serialize tx extra burn amount " ) ;
2022-09-13 08:57:56 +02:00
return false ;
}
return true ;
2019-10-30 22:28:47 +01:00
}
//---------------------------------------------------------------
2014-03-03 23:07:58 +01:00
bool get_inputs_money_amount ( const transaction & tx , uint64_t & money )
{
money = 0 ;
2017-01-22 21:38:10 +01:00
for ( const auto & in : tx . vin )
2014-03-03 23:07:58 +01:00
{
2020-06-02 05:47:20 +02:00
CHECKED_GET_SPECIFIC_VARIANT ( in , txin_to_key , tokey_in , false ) ;
2014-03-03 23:07:58 +01:00
money + = tokey_in . amount ;
}
return true ;
}
//---------------------------------------------------------------
uint64_t get_block_height ( const block & b )
{
2022-04-29 01:51:14 +02:00
cryptonote : : block bl = b ;
if ( b . miner_tx . vout . size ( ) > 0 )
{
CHECK_AND_ASSERT_MES ( b . miner_tx . vin . size ( ) = = 1 , 0 , " wrong miner tx in block: " < < get_block_hash ( b ) < < " , b.miner_tx.vin.size() != 1 (size is: " < < b . miner_tx . vin . size ( ) < < " ) " ) ;
CHECKED_GET_SPECIFIC_VARIANT ( b . miner_tx . vin [ 0 ] , txin_gen , coinbase_in , 0 ) ;
2022-05-20 22:55:07 +02:00
if ( b . major_version > = hf : : hf19_reward_batching )
2022-04-29 01:51:14 +02:00
{
CHECK_AND_ASSERT_MES ( coinbase_in . height = = b . height , 0 , " wrong miner tx in block: " < < get_block_hash ( b ) ) ;
}
return coinbase_in . height ;
} else {
return b . height ;
}
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
bool check_inputs_types_supported ( const transaction & tx )
{
2017-01-22 21:38:10 +01:00
for ( const auto & in : tx . vin )
2014-03-03 23:07:58 +01:00
{
2020-06-02 05:47:20 +02:00
CHECK_AND_ASSERT_MES ( std : : holds_alternative < txin_to_key > ( in ) , false , " wrong variant type: "
< < tools : : type_name ( tools : : variant_type ( in ) ) < < " , expected " < < tools : : type_name < txin_to_key > ( )
2014-03-03 23:07:58 +01:00
< < " , in transaction id= " < < get_transaction_hash ( tx ) ) ;
}
return true ;
}
//-----------------------------------------------------------------------------------------------
bool check_outs_valid ( const transaction & tx )
{
2022-09-13 08:57:56 +02:00
if ( ! tx . is_transfer ( ) & & tx . vout . size ( ) ! = 0 )
2018-07-25 03:13:38 +02:00
{
2022-10-08 04:30:29 +02:00
log : : warning ( logcat , " tx type: {} must have 0 outputs, received: {}, id={} " , tx . type , tx . vout . size ( ) , get_transaction_hash ( tx ) ) ;
2022-09-13 08:57:56 +02:00
return false ;
2018-07-25 03:13:38 +02:00
}
2022-09-13 08:57:56 +02:00
if ( tx . version > = txversion : : v3_per_output_unlock_times & & tx . vout . size ( ) ! = tx . output_unlock_times . size ( ) )
2018-08-03 03:39:28 +02:00
{
2022-10-08 04:30:29 +02:00
log : : warning ( logcat , " tx version: {} must have equal number of output unlock times and outputs " , tx . version ) ;
2022-09-13 08:57:56 +02:00
return false ;
2018-08-03 03:39:28 +02:00
}
2017-01-22 21:38:10 +01:00
for ( const tx_out & out : tx . vout )
2014-03-03 23:07:58 +01:00
{
2020-06-02 05:47:20 +02:00
CHECK_AND_ASSERT_MES ( std : : holds_alternative < txout_to_key > ( out . target ) , false , " wrong variant type: "
< < tools : : type_name ( tools : : variant_type ( out . target ) ) < < " , expected " < < tools : : type_name < txout_to_key > ( )
2014-03-03 23:07:58 +01:00
< < " , in transaction id= " < < get_transaction_hash ( tx ) ) ;
2019-06-11 20:53:46 +02:00
if ( tx . version = = txversion : : v1 )
2016-06-16 00:37:13 +02:00
{
2022-09-13 08:57:56 +02:00
if ( out . amount < = 0 )
{
2022-09-23 01:27:12 +02:00
log : : warning ( logcat , " zero amount output in transaction id={} " , get_transaction_hash ( tx ) ) ;
2022-09-13 08:57:56 +02:00
return false ;
}
2016-06-16 00:37:13 +02:00
}
2014-03-03 23:07:58 +01:00
2020-10-16 00:44:36 +02:00
if ( ! check_key ( var : : get < txout_to_key > ( out . target ) . key ) )
2014-03-03 23:07:58 +01:00
return false ;
}
return true ;
}
//-----------------------------------------------------------------------------------------------
bool check_money_overflow ( const transaction & tx )
{
return check_inputs_overflow ( tx ) & & check_outs_overflow ( tx ) ;
}
//---------------------------------------------------------------
bool check_inputs_overflow ( const transaction & tx )
{
uint64_t money = 0 ;
2017-01-22 21:38:10 +01:00
for ( const auto & in : tx . vin )
2014-03-03 23:07:58 +01:00
{
2020-06-02 05:47:20 +02:00
CHECKED_GET_SPECIFIC_VARIANT ( in , txin_to_key , tokey_in , false ) ;
2014-03-03 23:07:58 +01:00
if ( money > tokey_in . amount + money )
return false ;
money + = tokey_in . amount ;
}
return true ;
}
//---------------------------------------------------------------
bool check_outs_overflow ( const transaction & tx )
{
uint64_t money = 0 ;
2017-01-22 21:38:10 +01:00
for ( const auto & o : tx . vout )
2014-03-03 23:07:58 +01:00
{
if ( money > o . amount + money )
return false ;
money + = o . amount ;
}
return true ;
}
//---------------------------------------------------------------
uint64_t get_outs_money_amount ( const transaction & tx )
{
uint64_t outputs_amount = 0 ;
2017-01-22 21:38:10 +01:00
for ( const auto & o : tx . vout )
2014-03-03 23:07:58 +01:00
outputs_amount + = o . amount ;
return outputs_amount ;
}
//---------------------------------------------------------------
std : : string short_hash_str ( const crypto : : hash & h )
{
2022-02-10 19:25:55 +01:00
return oxenc : : to_hex ( tools : : view_guts ( h ) . substr ( 0 , 4 ) ) + " .... " ;
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
2017-02-19 03:42:10 +01:00
bool is_out_to_acc ( const account_keys & acc , const txout_to_key & out_key , const crypto : : public_key & tx_pub_key , const std : : vector < crypto : : public_key > & additional_tx_pub_keys , size_t output_index )
2014-03-03 23:07:58 +01:00
{
crypto : : key_derivation derivation ;
2018-03-05 08:16:30 +01:00
bool r = acc . get_device ( ) . generate_key_derivation ( tx_pub_key , acc . m_view_secret_key , derivation ) ;
2017-12-12 11:58:27 +01:00
CHECK_AND_ASSERT_MES ( r , false , " Failed to generate key derivation " ) ;
2014-03-03 23:07:58 +01:00
crypto : : public_key pk ;
2018-03-05 08:16:30 +01:00
r = acc . get_device ( ) . derive_public_key ( derivation , output_index , acc . m_account_address . m_spend_public_key , pk ) ;
2017-12-12 11:58:27 +01:00
CHECK_AND_ASSERT_MES ( r , false , " Failed to derive public key " ) ;
2017-02-19 03:42:10 +01:00
if ( pk = = out_key . key )
return true ;
// try additional tx pubkeys if available
if ( ! additional_tx_pub_keys . empty ( ) )
{
CHECK_AND_ASSERT_MES ( output_index < additional_tx_pub_keys . size ( ) , false , " wrong number of additional tx pubkeys " ) ;
2018-03-05 08:16:30 +01:00
r = acc . get_device ( ) . generate_key_derivation ( additional_tx_pub_keys [ output_index ] , acc . m_view_secret_key , derivation ) ;
2017-12-12 11:58:27 +01:00
CHECK_AND_ASSERT_MES ( r , false , " Failed to generate key derivation " ) ;
2018-03-05 08:16:30 +01:00
r = acc . get_device ( ) . derive_public_key ( derivation , output_index , acc . m_account_address . m_spend_public_key , pk ) ;
2017-12-12 11:58:27 +01:00
CHECK_AND_ASSERT_MES ( r , false , " Failed to derive public key " ) ;
2017-02-19 03:42:10 +01:00
return pk = = out_key . key ;
}
return false ;
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
2020-06-02 00:30:19 +02:00
std : : optional < subaddress_receive_info > is_out_to_acc_precomp ( const std : : unordered_map < crypto : : public_key , subaddress_index > & subaddresses , const crypto : : public_key & out_key , const crypto : : key_derivation & derivation , const std : : vector < crypto : : key_derivation > & additional_derivations , size_t output_index , hw : : device & hwdev )
2016-11-01 17:24:04 +01:00
{
2017-02-19 03:42:10 +01:00
// try the shared tx pubkey
crypto : : public_key subaddress_spendkey ;
2018-03-05 08:16:30 +01:00
hwdev . derive_subaddress_public_key ( out_key , derivation , output_index , subaddress_spendkey ) ;
2017-02-19 03:42:10 +01:00
auto found = subaddresses . find ( subaddress_spendkey ) ;
if ( found ! = subaddresses . end ( ) )
return subaddress_receive_info { found - > second , derivation } ;
// try additional tx pubkeys if available
if ( ! additional_derivations . empty ( ) )
{
2020-06-02 00:30:19 +02:00
CHECK_AND_ASSERT_MES ( output_index < additional_derivations . size ( ) , std : : nullopt , " wrong number of additional derivations " ) ;
2018-03-05 08:16:30 +01:00
hwdev . derive_subaddress_public_key ( out_key , additional_derivations [ output_index ] , output_index , subaddress_spendkey ) ;
2017-02-19 03:42:10 +01:00
found = subaddresses . find ( subaddress_spendkey ) ;
if ( found ! = subaddresses . end ( ) )
return subaddress_receive_info { found - > second , additional_derivations [ output_index ] } ;
}
2020-06-02 00:30:19 +02:00
return std : : nullopt ;
2016-11-01 17:24:04 +01:00
}
//---------------------------------------------------------------
2014-03-03 23:07:58 +01:00
bool lookup_acc_outs ( const account_keys & acc , const transaction & tx , std : : vector < size_t > & outs , uint64_t & money_transfered )
{
2014-05-03 18:19:43 +02:00
crypto : : public_key tx_pub_key = get_tx_pub_key_from_extra ( tx ) ;
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
if ( ! tx_pub_key )
2014-05-03 18:19:43 +02:00
return false ;
2017-02-19 03:42:10 +01:00
std : : vector < crypto : : public_key > additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra ( tx ) ;
return lookup_acc_outs ( acc , tx , tx_pub_key , additional_tx_pub_keys , outs , money_transfered ) ;
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
2017-02-19 03:42:10 +01:00
bool lookup_acc_outs ( const account_keys & acc , const transaction & tx , const crypto : : public_key & tx_pub_key , const std : : vector < crypto : : public_key > & additional_tx_pub_keys , std : : vector < size_t > & outs , uint64_t & money_transfered )
2014-03-03 23:07:58 +01:00
{
2017-02-19 03:42:10 +01:00
CHECK_AND_ASSERT_MES ( additional_tx_pub_keys . empty ( ) | | additional_tx_pub_keys . size ( ) = = tx . vout . size ( ) , false , " wrong number of additional pubkeys " ) ;
2014-03-03 23:07:58 +01:00
money_transfered = 0 ;
size_t i = 0 ;
2017-01-22 21:38:10 +01:00
for ( const tx_out & o : tx . vout )
2014-03-03 23:07:58 +01:00
{
2020-06-02 05:47:20 +02:00
CHECK_AND_ASSERT_MES ( std : : holds_alternative < txout_to_key > ( o . target ) , false , " wrong type id in transaction out " ) ;
2020-10-16 00:44:36 +02:00
if ( is_out_to_acc ( acc , var : : get < txout_to_key > ( o . target ) , tx_pub_key , additional_tx_pub_keys , i ) )
2014-03-03 23:07:58 +01:00
{
outs . push_back ( i ) ;
money_transfered + = o . amount ;
}
i + + ;
}
return true ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
void get_blob_hash ( const std : : string_view blob , crypto : : hash & res )
2014-03-03 23:07:58 +01:00
{
cn_fast_hash ( blob . data ( ) , blob . size ( ) , res ) ;
}
//---------------------------------------------------------------
2022-04-15 22:26:07 +02:00
std : : string print_money ( uint64_t amount , bool strip_zeros )
2017-03-01 23:27:27 +01:00
{
2022-05-16 22:55:05 +02:00
constexpr unsigned int decimal_point = oxen : : DISPLAY_DECIMAL_POINT ;
2014-03-03 23:07:58 +01:00
std : : string s = std : : to_string ( amount ) ;
2017-03-01 23:27:27 +01:00
if ( s . size ( ) < decimal_point + 1 )
2014-03-03 23:07:58 +01:00
{
2017-03-01 23:27:27 +01:00
s . insert ( 0 , decimal_point + 1 - s . size ( ) , ' 0 ' ) ;
2014-03-03 23:07:58 +01:00
}
2022-04-15 22:26:07 +02:00
s . insert ( s . size ( ) - decimal_point , " . " ) ;
if ( strip_zeros )
{
2021-08-06 18:56:20 +02:00
while ( s . back ( ) = = ' 0 ' )
s . pop_back ( ) ;
if ( s . back ( ) = = ' . ' )
s . pop_back ( ) ;
}
2014-03-03 23:07:58 +01:00
return s ;
}
//---------------------------------------------------------------
2022-04-15 22:26:07 +02:00
std : : string format_money ( uint64_t amount , bool strip_zeros )
{
auto value = print_money ( amount , strip_zeros ) ;
value + = ' ' ;
value + = get_unit ( ) ;
return value ;
}
//---------------------------------------------------------------
2019-10-26 05:05:20 +02:00
std : : string print_tx_verification_context ( tx_verification_context const & tvc , transaction const * tx )
{
std : : ostringstream os ;
2020-03-04 23:39:11 +01:00
if ( tvc . m_verbose_error . size ( ) )
os < < tvc . m_verbose_error < < " \n " ;
2019-10-26 05:05:20 +02:00
if ( tvc . m_verifivation_failed ) os < < " Verification failed, connection should be dropped, " ; //bad tx, should drop connection
if ( tvc . m_verifivation_impossible ) os < < " Verification impossible, related to alt chain, " ; //the transaction is related with an alternative blockchain
2021-08-26 21:22:07 +02:00
if ( ! tvc . m_should_be_relayed ) os < < " TX should NOT be relayed, " ;
2019-10-26 05:05:20 +02:00
if ( tvc . m_added_to_pool ) os < < " TX added to pool, " ;
if ( tvc . m_low_mixin ) os < < " Insufficient mixin, " ;
if ( tvc . m_double_spend ) os < < " Double spend TX, " ;
if ( tvc . m_invalid_input ) os < < " Invalid inputs, " ;
if ( tvc . m_invalid_output ) os < < " Invalid outputs, " ;
2020-06-04 08:49:18 +02:00
if ( tvc . m_too_few_outputs ) os < < " Need at least 2 outputs, " ;
2019-10-26 05:05:20 +02:00
if ( tvc . m_too_big ) os < < " TX too big, " ;
if ( tvc . m_overspend ) os < < " Overspend, " ;
if ( tvc . m_fee_too_low ) os < < " Fee too low, " ;
if ( tvc . m_invalid_version ) os < < " TX has invalid version, " ;
if ( tvc . m_invalid_type ) os < < " TX has invalid type, " ;
if ( tvc . m_key_image_locked_by_snode ) os < < " Key image is locked by service node, " ;
if ( tvc . m_key_image_blacklisted ) os < < " Key image is blacklisted on the service node network, " ;
2019-01-25 04:15:52 +01:00
if ( tx )
2022-10-08 04:30:29 +02:00
os < < " TX Version: {}, Type: {} " _format ( tx - > version , tx - > type ) ;
2019-01-25 04:15:52 +01:00
2019-10-26 05:05:20 +02:00
std : : string buf = os . str ( ) ;
if ( buf . size ( ) > = 2 & & buf [ buf . size ( ) - 2 ] = = ' , ' )
buf . resize ( buf . size ( ) - 2 ) ;
2018-08-15 03:47:45 +02:00
return buf ;
}
2022-03-17 06:42:52 +01:00
//---------------------------------------------------------------
2021-08-26 21:22:07 +02:00
std : : unordered_set < std : : string > tx_verification_failure_codes ( const tx_verification_context & tvc ) {
std : : unordered_set < std : : string > reasons ;
if ( tvc . m_verifivation_failed ) reasons . insert ( " failed " ) ;
if ( tvc . m_verifivation_impossible ) reasons . insert ( " altchain " ) ;
if ( tvc . m_low_mixin ) reasons . insert ( " mixin " ) ;
if ( tvc . m_double_spend ) reasons . insert ( " double_spend " ) ;
if ( tvc . m_invalid_input ) reasons . insert ( " invalid_input " ) ;
if ( tvc . m_invalid_output ) reasons . insert ( " invalid_output " ) ;
if ( tvc . m_too_few_outputs ) reasons . insert ( " too_few_outputs " ) ;
if ( tvc . m_too_big ) reasons . insert ( " too_big " ) ;
if ( tvc . m_overspend ) reasons . insert ( " overspend " ) ;
if ( tvc . m_fee_too_low ) reasons . insert ( " fee_too_low " ) ;
if ( tvc . m_invalid_version ) reasons . insert ( " invalid_version " ) ;
if ( tvc . m_invalid_type ) reasons . insert ( " invalid_type " ) ;
if ( tvc . m_key_image_locked_by_snode ) reasons . insert ( " snode_locked " ) ;
if ( tvc . m_key_image_blacklisted ) reasons . insert ( " blacklisted " ) ;
if ( ! tvc . m_should_be_relayed ) reasons . insert ( " not_relayed " ) ;
return reasons ;
}
2018-08-15 03:47:45 +02:00
//---------------------------------------------------------------
2019-10-26 05:05:20 +02:00
std : : string print_vote_verification_context ( vote_verification_context const & vvc , service_nodes : : quorum_vote_t const * vote )
2018-08-15 03:47:45 +02:00
{
2019-10-26 05:05:20 +02:00
std : : ostringstream os ;
2018-08-15 03:47:45 +02:00
2019-10-26 05:05:20 +02:00
if ( vvc . m_invalid_block_height ) os < < " Invalid block height: " < < ( vote ? std : : to_string ( vote - > block_height ) : " ?? " ) < < " , " ;
if ( vvc . m_duplicate_voters ) os < < " Index in group was duplicated: " < < ( vote ? std : : to_string ( vote - > index_in_group ) : " ?? " ) < < " , " ;
if ( vvc . m_validator_index_out_of_bounds ) os < < " Validator index out of bounds " ;
if ( vvc . m_worker_index_out_of_bounds ) os < < " Worker index out of bounds: " < < ( vote ? std : : to_string ( vote - > state_change . worker_index ) : " ?? " ) < < " , " ;
if ( vvc . m_signature_not_valid ) os < < " Signature not valid, " ;
if ( vvc . m_added_to_pool ) os < < " Added to pool, " ;
if ( vvc . m_not_enough_votes ) os < < " Not enough votes, " ;
2019-05-31 03:06:42 +02:00
if ( vvc . m_incorrect_voting_group )
{
2019-10-26 05:05:20 +02:00
os < < " Incorrect voting group specified " ;
2019-05-31 03:06:42 +02:00
if ( vote )
2019-08-07 02:52:32 +02:00
{
if ( vote - > group = = service_nodes : : quorum_group : : validator )
2019-10-26 05:05:20 +02:00
os < < " : validator " ;
2019-08-07 02:52:32 +02:00
else if ( vote - > group = = service_nodes : : quorum_group : : worker )
2019-10-26 05:05:20 +02:00
os < < " : worker " ;
2019-08-07 02:52:32 +02:00
else
2019-10-26 05:05:20 +02:00
os < < " : " < < static_cast < int > ( vote - > group ) ;
2019-08-07 02:52:32 +02:00
}
2019-10-26 05:05:20 +02:00
os < < " , " ;
2019-05-31 03:06:42 +02:00
}
2019-10-26 05:05:20 +02:00
if ( vvc . m_invalid_vote_type ) os < < " Vote type has invalid value: " < < ( vote ? std : : to_string ( ( uint8_t ) vote - > type ) : " ?? " ) < < " , " ;
if ( vvc . m_votes_not_sorted ) os < < " Votes are not stored in ascending order " ;
2018-08-15 03:47:45 +02:00
2019-10-26 05:05:20 +02:00
std : : string buf = os . str ( ) ;
if ( buf . size ( ) > = 2 & & buf [ buf . size ( ) - 2 ] = = ' , ' )
buf . resize ( buf . size ( ) - 2 ) ;
2019-01-25 04:15:52 +01:00
2018-12-21 01:33:05 +01:00
return buf ;
2018-08-15 03:47:45 +02:00
}
//---------------------------------------------------------------
2021-04-14 07:11:22 +02:00
bool is_valid_address ( const std : : string address , cryptonote : : network_type nettype , bool allow_subaddress , bool allow_integrated )
2021-04-12 07:10:24 +02:00
{
cryptonote : : address_parse_info addr_info ;
bool valid = false ;
2021-04-14 07:11:22 +02:00
if ( get_account_address_from_str ( addr_info , nettype , address ) )
{
if ( addr_info . is_subaddress )
valid = allow_subaddress ;
else if ( addr_info . has_payment_id )
valid = allow_integrated ;
else
valid = true ;
2021-04-12 07:10:24 +02:00
}
return valid ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
crypto : : hash get_blob_hash ( const std : : string_view blob )
2018-11-11 14:39:00 +01:00
{
2020-06-02 05:08:48 +02:00
crypto : : hash h ;
2018-11-11 14:39:00 +01:00
get_blob_hash ( blob , h ) ;
return h ;
}
//---------------------------------------------------------------
2014-03-03 23:07:58 +01:00
crypto : : hash get_transaction_hash ( const transaction & t )
{
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
crypto : : hash h { } ;
2016-08-09 22:34:09 +02:00
get_transaction_hash ( t , h , NULL ) ;
2019-03-19 02:07:10 +01:00
CHECK_AND_ASSERT_THROW_MES ( get_transaction_hash ( t , h , NULL ) , " Failed to calculate transaction hash " ) ;
2014-03-03 23:07:58 +01:00
return h ;
}
//---------------------------------------------------------------
bool get_transaction_hash ( const transaction & t , crypto : : hash & res )
{
2016-08-09 22:34:09 +02:00
return get_transaction_hash ( t , res , NULL ) ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
[[nodiscard]] bool calculate_transaction_prunable_hash ( const transaction & t , const std : : string * blob , crypto : : hash & res )
2017-10-01 12:24:33 +02:00
{
2019-06-11 20:53:46 +02:00
if ( t . version = = txversion : : v1 )
2017-10-01 12:24:33 +02:00
return false ;
2018-11-11 14:39:00 +01:00
const unsigned int unprunable_size = t . unprunable_size ;
if ( blob & & unprunable_size )
{
CHECK_AND_ASSERT_MES ( unprunable_size < = blob - > size ( ) , false , " Inconsistent transaction unprunable and blob sizes " ) ;
2020-06-02 05:08:48 +02:00
cryptonote : : get_blob_hash ( std : : string_view { * blob } . substr ( unprunable_size ) , res ) ;
2018-11-11 14:39:00 +01:00
}
else
{
2020-06-02 05:08:48 +02:00
serialization : : binary_string_archiver ba ;
2020-06-02 05:47:20 +02:00
size_t mixin = 0 ;
if ( t . vin . size ( ) > 0 & & std : : holds_alternative < txin_to_key > ( t . vin [ 0 ] ) )
2020-10-16 00:44:36 +02:00
mixin = var : : get < txin_to_key > ( t . vin [ 0 ] ) . key_offsets . size ( ) - 1 ;
2020-06-02 05:08:48 +02:00
try {
2020-11-23 23:25:01 +01:00
const_cast < transaction & > ( t ) . rct_signatures . p . serialize_rctsig_prunable (
ba , t . rct_signatures . type , t . vin . size ( ) , t . vout . size ( ) , mixin ) ;
2020-06-02 05:08:48 +02:00
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : error ( logcat , " Failed to serialize rct signatures (prunable): {} " , e . what ( ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
}
cryptonote : : get_blob_hash ( ba . str ( ) , res ) ;
2018-11-11 14:39:00 +01:00
}
2017-10-01 12:24:33 +02:00
return true ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
crypto : : hash get_transaction_prunable_hash ( const transaction & t , const std : : string * blobdata )
2017-10-01 12:24:33 +02:00
{
crypto : : hash res ;
2018-11-11 14:39:00 +01:00
CHECK_AND_ASSERT_THROW_MES ( calculate_transaction_prunable_hash ( t , blobdata , res ) , " Failed to calculate tx prunable hash " ) ;
2017-10-01 12:24:33 +02:00
return res ;
}
//---------------------------------------------------------------
crypto : : hash get_pruned_transaction_hash ( const transaction & t , const crypto : : hash & pruned_data_hash )
{
// v1 transactions hash the entire blob
2020-06-02 05:08:48 +02:00
if ( t . version < txversion : : v2_ringct )
throw std : : runtime_error ( " Hash for pruned v1 tx cannot be calculated " ) ;
2017-10-01 12:24:33 +02:00
// v2 transactions hash different parts together, than hash the set of those hashes
crypto : : hash hashes [ 3 ] ;
// prefix
get_transaction_prefix_hash ( t , hashes [ 0 ] ) ;
transaction & tt = const_cast < transaction & > ( t ) ;
// base rct
{
2020-06-02 05:08:48 +02:00
serialization : : binary_string_archiver ba ;
2017-10-01 12:24:33 +02:00
const size_t inputs = t . vin . size ( ) ;
const size_t outputs = t . vout . size ( ) ;
2020-06-02 05:08:48 +02:00
tt . rct_signatures . serialize_rctsig_base ( ba , inputs , outputs ) ; // throws on error (good)
cryptonote : : get_blob_hash ( ba . str ( ) , hashes [ 1 ] ) ;
2017-10-01 12:24:33 +02:00
}
// prunable rct
2020-11-21 05:20:15 +01:00
if ( t . rct_signatures . type = = rct : : RCTType : : Null )
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
hashes [ 2 ] . zero ( ) ;
2019-03-20 13:11:24 +01:00
else
hashes [ 2 ] = pruned_data_hash ;
2017-10-01 12:24:33 +02:00
// the tx hash is the hash of the 3 hashes
crypto : : hash res = cn_fast_hash ( hashes , sizeof ( hashes ) ) ;
return res ;
}
//---------------------------------------------------------------
2017-03-22 19:01:09 +01:00
bool calculate_transaction_hash ( const transaction & t , crypto : : hash & res , size_t * blob_size )
2016-08-09 22:34:09 +02:00
{
// v1 transactions hash the entire blob
2019-06-11 20:53:46 +02:00
if ( t . version = = txversion : : v1 )
2016-08-09 22:34:09 +02:00
{
size_t ignored_blob_size , & blob_size_ref = blob_size ? * blob_size : ignored_blob_size ;
return get_object_hash ( t , res , blob_size_ref ) ;
}
// v2 transactions hash different parts together, than hash the set of those hashes
crypto : : hash hashes [ 3 ] ;
// prefix
get_transaction_prefix_hash ( t , hashes [ 0 ] ) ;
2022-05-20 23:29:48 +02:00
const std : : string blob = tx_to_blob ( t ) ;
2020-05-31 18:50:08 +02:00
CHECK_AND_ASSERT_MES ( ! blob . empty ( ) , false , " Failed to convert tx to blob " ) ;
2018-11-11 14:39:00 +01:00
2021-01-04 01:09:45 +01:00
// TODO(oxen): Not sure if this is the right fix, we may just want to set
2019-04-11 07:08:26 +02:00
// unprunable size to the size of the prefix because technically that is
// what it is and then keep this code path.
2019-11-29 04:36:43 +01:00
if ( t . is_transfer ( ) )
2016-09-14 21:23:06 +02:00
{
2019-04-11 07:08:26 +02:00
const unsigned int unprunable_size = t . unprunable_size ;
const unsigned int prefix_size = t . prefix_size ;
// base rct
2020-05-31 18:50:08 +02:00
CHECK_AND_ASSERT_MES ( prefix_size < = unprunable_size & & unprunable_size < = blob . size ( ) , false ,
" Inconsistent transaction prefix ( " < < prefix_size < < " ), unprunable ( " < < unprunable_size < < " ) and blob ( " < < blob . size ( ) < < " ) sizes in: " < < __func__ ) ;
2020-06-02 05:08:48 +02:00
cryptonote : : get_blob_hash ( std : : string_view { blob } . substr ( prefix_size , unprunable_size - prefix_size ) , hashes [ 1 ] ) ;
2019-04-11 07:08:26 +02:00
}
else
{
2019-05-28 06:00:13 +02:00
transaction & tt = const_cast < transaction & > ( t ) ;
2020-06-02 05:08:48 +02:00
serialization : : binary_string_archiver ba ;
try {
tt . rct_signatures . serialize_rctsig_base ( ba , t . vin . size ( ) , t . vout . size ( ) ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : error ( logcat , " Failed to serialize rct signatures base: {} " , e . what ( ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
}
cryptonote : : get_blob_hash ( ba . str ( ) , hashes [ 1 ] ) ;
2016-09-14 21:23:06 +02:00
}
// prunable rct
2020-11-21 05:20:15 +01:00
if ( t . rct_signatures . type = = rct : : RCTType : : Null )
2016-09-14 21:23:06 +02:00
{
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
hashes [ 2 ] . zero ( ) ;
2016-09-14 21:23:06 +02:00
}
2020-06-02 05:08:48 +02:00
else if ( ! calculate_transaction_prunable_hash ( t , & blob , hashes [ 2 ] ) )
2016-09-14 21:23:06 +02:00
{
2022-09-23 01:27:12 +02:00
log : : error ( logcat , " Failed to get tx prunable hash " ) ;
2020-06-02 05:08:48 +02:00
return false ;
2016-09-14 21:23:06 +02:00
}
2016-08-09 22:34:09 +02:00
// the tx hash is the hash of the 3 hashes
res = cn_fast_hash ( hashes , sizeof ( hashes ) ) ;
// we still need the size
if ( blob_size )
2018-12-14 01:22:34 +01:00
{
if ( ! t . is_blob_size_valid ( ) )
{
t . blob_size = blob . size ( ) ;
t . set_blob_size_valid ( true ) ;
}
* blob_size = t . blob_size ;
}
2016-08-09 22:34:09 +02:00
return true ;
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
2017-03-22 19:01:09 +01:00
bool get_transaction_hash ( const transaction & t , crypto : : hash & res , size_t * blob_size )
{
2017-03-25 10:18:53 +01:00
if ( t . is_hash_valid ( ) )
2017-03-22 19:01:09 +01:00
{
res = t . hash ;
if ( blob_size )
{
2017-03-25 10:18:53 +01:00
if ( ! t . is_blob_size_valid ( ) )
2017-03-22 19:01:09 +01:00
{
t . blob_size = get_object_blobsize ( t ) ;
2017-03-25 10:18:53 +01:00
t . set_blob_size_valid ( true ) ;
2017-03-22 19:01:09 +01:00
}
* blob_size = t . blob_size ;
}
return true ;
}
bool ret = calculate_transaction_hash ( t , res , blob_size ) ;
if ( ! ret )
return false ;
t . hash = res ;
2017-03-25 10:18:53 +01:00
t . set_hash_valid ( true ) ;
2017-03-22 19:01:09 +01:00
if ( blob_size )
{
t . blob_size = * blob_size ;
2017-03-25 10:18:53 +01:00
t . set_blob_size_valid ( true ) ;
2017-03-22 19:01:09 +01:00
}
return true ;
}
//---------------------------------------------------------------
2014-03-03 23:07:58 +01:00
bool get_transaction_hash ( const transaction & t , crypto : : hash & res , size_t & blob_size )
{
2016-08-09 22:34:09 +02:00
return get_transaction_hash ( t , res , & blob_size ) ;
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
std : : string get_block_hashing_blob ( const block & b )
2014-03-03 23:07:58 +01:00
{
2022-05-20 23:29:48 +02:00
std : : string blob = t_serializable_object_to_blob ( static_cast < block_header > ( b ) ) ;
2014-04-02 18:00:17 +02:00
crypto : : hash tree_root_hash = get_tx_tree_hash ( b ) ;
2014-06-30 21:17:24 +02:00
blob . append ( reinterpret_cast < const char * > ( & tree_root_hash ) , sizeof ( tree_root_hash ) ) ;
2014-03-03 23:07:58 +01:00
blob . append ( tools : : get_varint_data ( b . tx_hashes . size ( ) + 1 ) ) ;
return blob ;
}
//---------------------------------------------------------------
2020-06-18 04:39:20 +02:00
bool calculate_block_hash ( const block & b , crypto : : hash & res )
2014-03-03 23:07:58 +01:00
{
2014-09-06 00:32:31 +02:00
bool hash_result = get_object_hash ( get_block_hashing_blob ( b ) , res ) ;
return hash_result ;
2014-03-03 23:07:58 +01:00
}
//---------------------------------------------------------------
2017-03-22 19:01:09 +01:00
bool get_block_hash ( const block & b , crypto : : hash & res )
{
2017-03-25 10:18:53 +01:00
if ( b . is_hash_valid ( ) )
2017-03-22 19:01:09 +01:00
{
res = b . hash ;
return true ;
}
bool ret = calculate_block_hash ( b , res ) ;
if ( ! ret )
return false ;
b . hash = res ;
2017-03-25 10:18:53 +01:00
b . set_hash_valid ( true ) ;
2017-03-22 19:01:09 +01:00
return true ;
}
//---------------------------------------------------------------
2014-03-03 23:07:58 +01:00
crypto : : hash get_block_hash ( const block & b )
{
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
crypto : : hash p { } ;
2014-03-03 23:07:58 +01:00
get_block_hash ( b , p ) ;
return p ;
}
//---------------------------------------------------------------
std : : vector < uint64_t > relative_output_offsets_to_absolute ( const std : : vector < uint64_t > & off )
{
std : : vector < uint64_t > res = off ;
for ( size_t i = 1 ; i < res . size ( ) ; i + + )
res [ i ] + = res [ i - 1 ] ;
return res ;
}
//---------------------------------------------------------------
std : : vector < uint64_t > absolute_output_offsets_to_relative ( const std : : vector < uint64_t > & off )
{
std : : vector < uint64_t > res = off ;
2022-05-24 01:17:50 +02:00
CHECK_AND_ASSERT_THROW_MES ( not off . empty ( ) , " absolute index to relative offset, no indices provided " ) ;
// vector must be sorted before calling this, else an index' offset would be negative
CHECK_AND_ASSERT_THROW_MES ( std : : is_sorted ( res . begin ( ) , res . end ( ) ) , " absolute index to relative offset, indices not sorted " ) ;
2014-03-03 23:07:58 +01:00
for ( size_t i = res . size ( ) - 1 ; i ! = 0 ; i - - )
res [ i ] - = res [ i - 1 ] ;
return res ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
[[nodiscard]] bool parse_and_validate_block_from_blob ( const std : : string_view b_blob , block & b , crypto : : hash * block_hash )
2014-03-03 23:07:58 +01:00
{
2020-06-02 05:08:48 +02:00
serialization : : binary_string_unarchiver ba { b_blob } ;
try {
serialization : : serialize ( ba , b ) ;
} catch ( const std : : exception & e ) {
2022-09-23 01:27:12 +02:00
log : : error ( logcat , " Failed to parse block from blob: {} " , e . what ( ) ) ;
2020-06-02 05:08:48 +02:00
return false ;
}
2017-03-25 10:18:53 +01:00
b . invalidate_hashes ( ) ;
b . miner_tx . invalidate_hashes ( ) ;
2018-12-13 20:47:47 +01:00
if ( block_hash )
{
2020-06-18 04:39:20 +02:00
calculate_block_hash ( b , * block_hash ) ;
2018-12-13 20:47:47 +01:00
b . hash = * block_hash ;
b . set_hash_valid ( true ) ;
}
2014-03-03 23:07:58 +01:00
return true ;
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool parse_and_validate_block_from_blob ( const std : : string_view b_blob , block & b )
2018-12-13 20:47:47 +01:00
{
2020-06-02 05:08:48 +02:00
return parse_and_validate_block_from_blob ( b_blob , b , nullptr ) ;
2018-12-13 20:47:47 +01:00
}
//---------------------------------------------------------------
2020-06-02 05:08:48 +02:00
bool parse_and_validate_block_from_blob ( const std : : string_view b_blob , block & b , crypto : : hash & block_hash )
2018-12-13 20:47:47 +01:00
{
return parse_and_validate_block_from_blob ( b_blob , b , & block_hash ) ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
std : : string block_to_blob ( const block & b )
2014-03-03 23:07:58 +01:00
{
return t_serializable_object_to_blob ( b ) ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
bool block_to_blob ( const block & b , std : : string & b_blob )
2014-03-03 23:07:58 +01:00
{
return t_serializable_object_to_blob ( b , b_blob ) ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
std : : string tx_to_blob ( const transaction & tx )
2014-03-03 23:07:58 +01:00
{
return t_serializable_object_to_blob ( tx ) ;
}
//---------------------------------------------------------------
2022-05-20 23:29:48 +02:00
bool tx_to_blob ( const transaction & tx , std : : string & b_blob )
2014-03-03 23:07:58 +01:00
{
return t_serializable_object_to_blob ( tx , b_blob ) ;
}
//---------------------------------------------------------------
void get_tx_tree_hash ( const std : : vector < crypto : : hash > & tx_hashes , crypto : : hash & h )
{
tree_hash ( tx_hashes . data ( ) , tx_hashes . size ( ) , h ) ;
}
//---------------------------------------------------------------
crypto : : hash get_tx_tree_hash ( const std : : vector < crypto : : hash > & tx_hashes )
{
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
crypto : : hash h { } ;
2014-03-03 23:07:58 +01:00
get_tx_tree_hash ( tx_hashes , h ) ;
return h ;
}
//---------------------------------------------------------------
crypto : : hash get_tx_tree_hash ( const block & b )
{
std : : vector < crypto : : hash > txs_ids ;
2018-12-14 01:22:34 +01:00
txs_ids . reserve ( 1 + b . tx_hashes . size ( ) ) ;
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
crypto : : hash h { } ;
2014-03-03 23:07:58 +01:00
size_t bl_sz = 0 ;
2019-03-19 02:07:10 +01:00
CHECK_AND_ASSERT_THROW_MES ( get_transaction_hash ( b . miner_tx , h , bl_sz ) , " Failed to calculate transaction hash " ) ;
2014-03-03 23:07:58 +01:00
txs_ids . push_back ( h ) ;
2017-01-22 21:38:10 +01:00
for ( auto & th : b . tx_hashes )
2014-03-03 23:07:58 +01:00
txs_ids . push_back ( th ) ;
return get_tx_tree_hash ( txs_ids ) ;
}
//---------------------------------------------------------------
2017-11-25 15:50:15 +01:00
crypto : : secret_key encrypt_key ( crypto : : secret_key key , const epee : : wipeable_string & passphrase )
2017-08-06 17:51:40 +02:00
{
crypto : : hash hash ;
2019-03-06 01:16:59 +01:00
crypto : : cn_slow_hash ( passphrase . data ( ) , passphrase . size ( ) , hash , crypto : : cn_slow_hash_type : : heavy_v1 ) ;
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
sc_add ( key . data ( ) , key . data ( ) , hash . data ( ) ) ;
2017-08-06 17:51:40 +02:00
return key ;
}
//---------------------------------------------------------------
2017-11-25 15:50:15 +01:00
crypto : : secret_key decrypt_key ( crypto : : secret_key key , const epee : : wipeable_string & passphrase )
2017-08-06 17:51:40 +02:00
{
crypto : : hash hash ;
2019-03-06 01:16:59 +01:00
crypto : : cn_slow_hash ( passphrase . data ( ) , passphrase . size ( ) , hash , crypto : : cn_slow_hash_type : : heavy_v1 ) ;
Overhaul and fix crypto::{public_key,ec_point,etc.} types
- Remove implicit `operator bool` from ec_point/public_key/etc. which
was causing all sorts of implicit conversion mess and bugs.
- Change ec_point/public_key/etc. to use a `std::array<unsigned char,
32>` (via a base type) rather than a C-array of char that has to be
reinterpret_cast<>'ed all over the place.
- Add methods to ec_point/public_key/etc. that make it work more like a
container of bytes (`.data()`, `.size()`, `operator[]`, `begin()`,
`end()`).
- Make a generic `crypto::null<T>` that is a constexpr all-0 `T`, rather
than the mishmash `crypto::null_hash`, crypto::null_pkey,
crypto::hash::null(), and so on.
- Replace three metric tons of `crypto::hash blahblah =
crypto::null_hash;` with the much simpler `crypto::hash blahblah{};`,
because there's no need to make a copy of a null hash in all these
cases. (Likewise for a few other null_whatevers).
- Remove a whole bunch of `if (blahblah == crypto::null_hash)` and `if
(blahblah != crypto::null_hash)` with the more concise `if
(!blahblah)` and `if (blahblah)` (which are fine via the newly
*explicit* bool conversion operators).
- `crypto::signature` becomes a 64-byte container (as above) but with
`c()` and `r()` to get the c() and r() data pointers. (Previously
`.c` and `.r` were `ec_scalar`s).
- Delete with great prejudice CRYPTO_MAKE_COMPARABLE and
CRYPTO_MAKE_HASHABLE and all the other utter trash in
`crypto/generic-ops.h`.
- De-inline functions in very common crypto/*.h files so that they don't
have to get compiled 300 times.
- Remove the disgusting include-a-C-header-inside-a-C++-namespace
garbage from some crypto headers trying to be both a C and *different*
C++ header at once.
- Remove the toxic, disgusting, shameful `operator&` on ec_scalar, etc.
that replace `&x` with `reinterpret_cast x into an unsigned char*`.
This was pure toxic waste.
- changed some `<<` outputs to fmt
- Random other small changes encountered while fixing everything that
cascaded out of the above changes.
2022-10-15 03:22:44 +02:00
sc_sub ( key . data ( ) , key . data ( ) , hash . data ( ) ) ;
2017-08-06 17:51:40 +02:00
return key ;
}
2020-03-13 06:07:14 +01:00
}