Compare commits

...

7 Commits

Author SHA1 Message Date
Some Random Crypto Guy 218911d9fc bumped RC version 2024-10-09 12:24:29 +01:00
Some Random Crypto Guy da3ef2511d fixed return_payment issues for N-out-TXs; fixed change_index being incorrect datatype; partial fix to asset_type RPC propagation issue 2024-10-09 12:21:50 +01:00
Some Random Crypto Guy 8b2b039036 N-out-TX support working for simple cases - needs edge case testing still 2024-10-08 12:03:20 +01:00
Some Random Crypto Guy d1eed6e9ff interim commit - NOT TESTED 2024-09-14 11:06:23 +01:00
Some Random Crypto Guy 30a2931067 fixed copy/paste glitch on previous 2024-09-09 12:01:15 +01:00
Some Random Crypto Guy 1c73dd0c9f switch to LWMA difficulty algorithm for HF2+ 2024-09-08 19:54:12 +01:00
Some Random Crypto Guy 1c84c00fe6 Merge branch 'main' into develop, ahead of new Salvium One development 2024-09-02 15:26:40 +01:00
22 changed files with 389 additions and 71 deletions
+11 -1
View File
@@ -1261,7 +1261,17 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
yield_tx_info yield_data;
yield_data.block_height = m_height;
yield_data.tx_hash = tx_hash;
yield_data.return_address = tx.return_address;
if (tx.version == TRANSACTION_VERSION_2_OUTS) {
if (tx.return_address == crypto::null_pkey)
throw0(DB_ERROR("missing return_address entry (needed to create yield data for PROTOCOL_TX) - v2 STAKE"));
yield_data.return_address = tx.return_address;
} else if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
if (tx.return_address_list.empty())
throw0(DB_ERROR("no return_address_list entry (needed to create yield data for the PROTOCOL_TX)"));
else if (tx.return_address_list.size() > 1)
throw0(DB_ERROR("too many return_address_list entries provided (only one needed to create yield data for the PROTOCOL_TX)"));
yield_data.return_address = tx.return_address_list[0];
}
yield_data.locked_coins = tx.amount_burnt;
if (tx.vin.empty())
throw0(DB_ERROR("tx.vin is empty (needed to create yield data for the PROTOCOL_TX)"));
+31
View File
@@ -133,6 +133,16 @@ monero_private_headers(blockchain_stats
${blockchain_stats_private_headers})
set(blockchain_scanner_sources
blockchain_scanner.cpp
)
set(blockchain_scanner_private_headers)
monero_private_headers(blockchain_scanner
${blockchain_scanner_private_headers})
monero_add_executable(blockchain_import
${blockchain_import_sources}
${blockchain_import_private_headers})
@@ -281,6 +291,27 @@ set_property(TARGET blockchain_depth
OUTPUT_NAME "salvium-blockchain-depth")
install(TARGETS blockchain_depth DESTINATION bin)
monero_add_executable(blockchain_scanner
${blockchain_scanner_sources}
${blockchain_scanner_private_headers})
target_link_libraries(blockchain_scanner
PRIVATE
cryptonote_core
blockchain_db
version
epee
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
set_property(TARGET blockchain_scanner
PROPERTY
OUTPUT_NAME "salvium-blockchain-scanner")
install(TARGETS blockchain_scanner DESTINATION bin)
monero_add_executable(blockchain_stats
${blockchain_stats_sources}
${blockchain_stats_private_headers})
Binary file not shown.
+13 -3
View File
@@ -200,8 +200,11 @@ namespace cryptonote
std::vector<uint8_t> extra;
// TX type
cryptonote::transaction_type type;
// Return address
crypto::public_key return_address;
// Return address list (must be at least 1 and at most BULLETPROOF_MAX_OUTPUTS-1 - the "-1" is for the change output)
std::vector<crypto::public_key> return_address_list;
//return_address_change_mask
std::vector<uint8_t> return_address_change_mask;
// Return TX public key
crypto::public_key return_pubkey;
// Source asset type
@@ -224,8 +227,13 @@ namespace cryptonote
if (type != cryptonote::transaction_type::PROTOCOL) {
VARINT_FIELD(amount_burnt)
if (type != cryptonote::transaction_type::MINER) {
FIELD(return_address)
FIELD(return_pubkey)
if (type == cryptonote::transaction_type::TRANSFER && version >= TRANSACTION_VERSION_N_OUTS) {
FIELD(return_address_list)
FIELD(return_address_change_mask)
} else {
FIELD(return_address)
FIELD(return_pubkey)
}
FIELD(source_asset_type)
FIELD(destination_asset_type)
VARINT_FIELD(amount_slippage_limit)
@@ -244,6 +252,8 @@ namespace cryptonote
extra.clear();
type = cryptonote::transaction_type::UNSET;
return_address = crypto::null_pkey;
return_address_list.clear();
return_address_change_mask.clear();
return_pubkey = crypto::null_pkey;
source_asset_type.clear();
destination_asset_type.clear();
@@ -166,24 +166,7 @@ namespace boost
inline void serialize(Archive &a, cryptonote::transaction_prefix &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.vin;
a & x.vout;
a & x.extra;
a & x.type;
if (x.type != cryptonote::transaction_type::MINER && x.type != cryptonote::transaction_type::PROTOCOL) {
a & x.return_address;
a & x.return_pubkey;
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_burnt;
a & x.amount_slippage_limit;
}
}
template <class Archive>
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.unlock_time;
a & x.vin;
a & x.vout;
a & x.extra;
@@ -191,8 +174,39 @@ namespace boost
if (x.type != cryptonote::transaction_type::PROTOCOL) {
a & x.amount_burnt;
if (x.type != cryptonote::transaction_type::MINER) {
a & x.return_address;
a & x.return_pubkey;
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
a & x.return_address_list;
a & x.return_address_change_mask;
} else {
a & x.return_address;
a & x.return_pubkey;
}
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_slippage_limit;
}
}
}
template <class Archive>
inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
{
a & x.version;
a & x.unlock_time;
a & x.vin;
a & x.vout;
a & x.extra;
a & x.type;
if (x.type != cryptonote::transaction_type::PROTOCOL) {
a & x.amount_burnt;
if (x.type != cryptonote::transaction_type::MINER) {
if (x.type == cryptonote::transaction_type::TRANSFER && x.version >= TRANSACTION_VERSION_N_OUTS) {
a & x.return_address_list;
a & x.return_address_change_mask;
} else {
a & x.return_address;
a & x.return_pubkey;
}
a & x.source_asset_type;
a & x.destination_asset_type;
a & x.amount_slippage_limit;
@@ -1724,7 +1724,7 @@ namespace cryptonote
blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
crypto::hash tree_root_hash = get_tx_tree_hash(b);
blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
blob.append(tools::get_varint_data(b.tx_hashes.size() + (b.major_version >= HF_VERSION_ENABLE_N_OUTS ? 2 : 1)));
return blob;
}
//---------------------------------------------------------------
+58
View File
@@ -33,6 +33,7 @@
#include <cstddef>
#include <cstdint>
#include <vector>
#include <boost/math/special_functions/round.hpp>
#include "int-util.h"
#include "crypto/hash.h"
@@ -239,6 +240,63 @@ namespace cryptonote {
return res.convert_to<difficulty_type>();
}
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
// LWMA difficulty algorithm
// Copyright (c) 2017-2018 Zawy
// MIT license http://www.opensource.org/licenses/mit-license.php.
// This is an improved version of Tom Harding's (Deger8) "WT-144"
// Karbowanec, Masari, Bitcoin Gold, and Bitcoin Cash have contributed.
// See https://github.com/zawy12/difficulty-algorithms/issues/3 for other algos.
// Do not use "if solvetime < 0 then solvetime = 1" which allows a catastrophic exploit.
// T= target_solvetime;
// N=45, 55, 70, 90, 120 for T=600, 240, 120, 90, and 60
const int64_t T = static_cast<int64_t>(target_seconds);
size_t N = DIFFICULTY_WINDOW;
if (timestamps.size() > N) {
timestamps.resize(N + 1);
cumulative_difficulties.resize(N + 1);
}
size_t n = timestamps.size();
assert(n == cumulative_difficulties.size());
assert(n <= DIFFICULTY_WINDOW);
// If new coin, just "give away" first 5 blocks at low difficulty
if ( n < 6 ) { return 1; }
// If height "n" is from 6 to N, then reset N to n-1.
else if (n < N+1) { N=n-1; }
// To get an average solvetime to within +/- ~0.1%, use an adjustment factor.
// adjust=0.99 for 90 < N < 130
const long double adjust = 0.998;
// The divisor k normalizes LWMA.
const long double k = N * (N + 1) / 2;
long double LWMA(0), sum_inverse_D(0), harmonic_mean_D(0), nextDifficulty(0);
int64_t solveTime(0);
uint64_t difficulty(0), next_difficulty(0);
// Loop through N most recent blocks.
for (size_t i = 1; i <= N; i++) {
solveTime = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i - 1]);
solveTime = std::min<int64_t>((T * 7), std::max<int64_t>(solveTime, (-7 * T)));
difficulty = (cumulative_difficulties[i] - cumulative_difficulties[i - 1]).convert_to<uint64_t>();
LWMA += (int64_t)(solveTime * i) / k;
sum_inverse_D += 1 / static_cast<double>(difficulty);
}
// Keep LWMA sane in case something unforeseen occurs.
if (static_cast<int64_t>(boost::math::round(LWMA)) < T / 20)
LWMA = static_cast<double>(T / 20);
harmonic_mean_D = N / sum_inverse_D * adjust;
nextDifficulty = harmonic_mean_D * T / LWMA;
next_difficulty = static_cast<uint64_t>(nextDifficulty);
return next_difficulty;
}
std::string hex(difficulty_type v)
{
static const char chars[] = "0123456789abcdef";
+2 -1
View File
@@ -58,6 +58,7 @@ namespace cryptonote
bool check_hash_128(const crypto::hash &hash, difficulty_type difficulty);
bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
std::string hex(difficulty_type v);
}
@@ -59,6 +59,7 @@ namespace cryptonote
bool m_fee_too_low;
bool m_too_few_outputs;
bool m_tx_extra_too_big;
bool m_version_mismatch; // TX version wrong for the currently-active HF version
};
struct block_verification_context
+8 -4
View File
@@ -42,7 +42,9 @@
#define CRYPTONOTE_MAX_TX_PER_BLOCK 0x10000000
#define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0
#define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60
#define CURRENT_TRANSACTION_VERSION 2
#define CURRENT_TRANSACTION_VERSION 3
#define TRANSACTION_VERSION_2_OUTS 2
#define TRANSACTION_VERSION_N_OUTS 3
#define CURRENT_BLOCK_MAJOR_VERSION 1
#define CURRENT_BLOCK_MINOR_VERSION 1
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
@@ -212,9 +214,11 @@
#define HF_VERSION_LONG_TERM_BLOCK_WEIGHT 2
#define HF_VERSION_2021_SCALING 2
#define HF_VERSION_ENABLE_CONVERT 2
#define HF_VERSION_ENABLE_ORACLE 2
#define HF_VERSION_SLIPPAGE_YIELD 2
#define HF_VERSION_ENABLE_N_OUTS 2
#define HF_VERSION_ENABLE_CONVERT 255
#define HF_VERSION_ENABLE_ORACLE 255
#define HF_VERSION_SLIPPAGE_YIELD 255
#define TESTNET_VERSION 11
#define STAGENET_VERSION 1
+58 -6
View File
@@ -967,7 +967,13 @@ start:
}
size_t target = get_difficulty_target();
difficulty_type diff = next_difficulty(timestamps, difficulties, target);
difficulty_type diff;
uint8_t version = get_current_hard_fork_version();
if (version == 1) {
diff = next_difficulty(timestamps, difficulties, target);
} else {
diff = next_difficulty_v2(timestamps, difficulties, target);
}
CRITICAL_REGION_LOCAL1(m_difficulty_lock);
m_difficulty_for_next_block_top_hash = top_hash;
@@ -1026,6 +1032,7 @@ size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_heig
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> difficulties;
uint8_t version = get_current_hard_fork_version();
timestamps.reserve(DIFFICULTY_BLOCKS_COUNT + 1);
difficulties.reserve(DIFFICULTY_BLOCKS_COUNT + 1);
if (start_height > 1)
@@ -1045,7 +1052,9 @@ size_t Blockchain::recalculate_difficulties(boost::optional<uint64_t> start_heig
for (uint64_t height = start_height; height <= top_height; ++height)
{
size_t target = DIFFICULTY_TARGET_V2;
difficulty_type recalculated_diff = next_difficulty(timestamps, difficulties, target);
difficulty_type recalculated_diff = (version == 1)
? next_difficulty(timestamps, difficulties, target)
: next_difficulty_v2(timestamps, difficulties, target);
boost::multiprecision::uint256_t recalculated_cum_diff_256 = boost::multiprecision::uint256_t(recalculated_diff) + last_cum_diff;
CHECK_AND_ASSERT_THROW_MES(recalculated_cum_diff_256 <= std::numeric_limits<difficulty_type>::max(), "Difficulty overflow!");
@@ -1299,6 +1308,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
LOG_PRINT_L3("Blockchain::" << __func__);
std::vector<uint64_t> timestamps;
std::vector<difficulty_type> cumulative_difficulties;
uint8_t version = get_current_hard_fork_version();
// if the alt chain isn't long enough to calculate the difficulty target
// based on its blocks alone, need to get more blocks from the main chain
@@ -1354,7 +1364,11 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
size_t target = DIFFICULTY_TARGET_V2;
// calculate the difficulty target for the block and return it
return next_difficulty(timestamps, cumulative_difficulties, target);
if (version == 1) {
return next_difficulty(timestamps, cumulative_difficulties, target);
} else {
return next_difficulty_v2(timestamps, cumulative_difficulties, target);
}
}
//------------------------------------------------------------------
// This function does a sanity check on basic things that all miner
@@ -1448,6 +1462,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl
switch (version) {
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
if (b.miner_tx.amount_burnt > 0) {
CHECK_AND_ASSERT_MES(money_in_use + b.miner_tx.amount_burnt > money_in_use, false, "miner transaction is overflowed by amount_burnt");
money_in_use += b.miner_tx.amount_burnt;
@@ -3576,6 +3591,43 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context
return true;
}
//------------------------------------------------------------------
bool Blockchain::check_tx_type_and_version(const transaction& tx, tx_verification_context &tvc) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock);
const uint8_t hf_version = m_hardfork->get_current_version();
// Prior to v2, only allow TX v2
if (hf_version < HF_VERSION_ENABLE_N_OUTS) {
// Check for N-out TXs
if (tx.version >= TRANSACTION_VERSION_N_OUTS) {
MERROR_VER("N-out TXs are not permitted prior to v" + std::to_string(HF_VERSION_ENABLE_N_OUTS));
tvc.m_version_mismatch = true;
return false;
}
// Check for v1 TXs - genesis block protocol_tx exception required!
if (tx.version == 1 && epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(tx)) == "4f78ff511e860acd03138737a71505eb62eb78b620e180e58c8e13ed0e1e3e19") {
MERROR("v1 TXs are not permitted");
tvc.m_version_mismatch = true;
return false;
}
}
// After v2 allow N-out TXs for TRANSFER ONLY
if (hf_version >= HF_VERSION_ENABLE_N_OUTS) {
if (tx.version >= TRANSACTION_VERSION_N_OUTS && tx.type != cryptonote::transaction_type::TRANSFER) {
MERROR("N-out TXs are only permitted for TRANSFER TX type");
tvc.m_version_mismatch = true;
return false;
}
}
return true;
}
//------------------------------------------------------------------
bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const
{
LOG_PRINT_L3("Blockchain::" << __func__);
@@ -3590,7 +3642,7 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const
bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector<std::vector<rct::ctkey>> &pubkeys, const uint8_t &hf_version)
{
PERF_TIMER(expand_transaction_2);
CHECK_AND_ASSERT_MES(tx.version == 2, false, "Transaction version is not 2");
CHECK_AND_ASSERT_MES(tx.version == 2 || tx.version == 3, false, "Transaction version is not 2/3");
rct::rctSig &rv = tx.rct_signatures;
@@ -3779,7 +3831,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc,
}
// min/max tx version based on HF, and we accept v1 txes if having a non mixable
const size_t max_tx_version = (hf_version < HF_VERSION_SLIPPAGE_YIELD) ? 2 : CURRENT_TRANSACTION_VERSION;
const size_t max_tx_version = (hf_version >= HF_VERSION_ENABLE_N_OUTS) ? TRANSACTION_VERSION_N_OUTS : TRANSACTION_VERSION_2_OUTS;
if (tx.version > max_tx_version)
{
MERROR_VER("transaction version " << (unsigned)tx.version << " is higher than max accepted version " << max_tx_version);
@@ -6056,7 +6108,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "7f60b4980ea16b32e3f9fc1959d9d4116ba91f2b067bd70b3e21c44520096d14";
static const char expected_block_hashes_hash[] = "b8639efef99951207b401131ed9f88e37c856a693d237fc6fad349b929aa1059";
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
if (get_checkpoints == nullptr || !m_fast_sync)
+13
View File
@@ -725,6 +725,19 @@ namespace cryptonote
*/
bool check_tx_outputs(const transaction& tx, tx_verification_context &tvc) const;
/**
* @brief check that a transaction's version & type conforms to current standards
*
* This function checks, for example at the time of this writing, that
* the TX version and type is supported by the current HF version on-chain.
*
* @param tx the transaction to check the version and type of
* @param tvc returned info about tx verification
*
* @return false if the TX version and/or type is unsupported, otherwise true
*/
bool check_tx_type_and_version(const transaction& tx, tx_verification_context &tvc) const;
/**
* @brief gets the block weight limit based on recent blocks
*
+2 -2
View File
@@ -842,8 +842,8 @@ namespace cryptonote
}
bad_semantics_txes_lock.unlock();
uint8_t version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = (version < HF_VERSION_SLIPPAGE_YIELD) ? 2 : CURRENT_TRANSACTION_VERSION;
uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version();
const size_t max_tx_version = (hf_version >= HF_VERSION_ENABLE_N_OUTS) ? TRANSACTION_VERSION_N_OUTS : TRANSACTION_VERSION_2_OUTS;
if (tx.version == 0 || tx.version > max_tx_version)
{
// v2 is the latest one we know
+58 -7
View File
@@ -46,6 +46,11 @@ using namespace epee;
#include "ringct/rctSigs.h"
#include "oracle/asset_types.h"
extern "C"
{
#include "crypto/keccak.h"
#include "crypto/crypto-ops.h"
}
using namespace crypto;
namespace cryptonote
@@ -583,6 +588,7 @@ namespace cryptonote
// Different forks take a different proportion of the block_reward for stakers
switch (hard_fork_version) {
case HF_VERSION_BULLETPROOF_PLUS:
case HF_VERSION_ENABLE_N_OUTS:
// SRCG: subtract 20% that will be rewarded to staking users
CHECK_AND_ASSERT_MES(tx.amount_burnt == 0, false, "while creating outs: amount_burnt is nonzero");
tx.amount_burnt = amount / 5;
@@ -653,8 +659,11 @@ namespace cryptonote
tx.set_null();
amount_keys.clear();
if (hf_version >= HF_VERSION_SLIPPAGE_YIELD) {
tx.version = 3;
tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
// Configure the correct TX version for the current HF + TX type
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
tx.version = TRANSACTION_VERSION_N_OUTS;
} else {
tx.version = 2;
}
@@ -662,8 +671,6 @@ namespace cryptonote
tx.extra = extra;
crypto::public_key txkey_pub;
tx.type = (tx_type == cryptonote::transaction_type::RETURN) ? cryptonote::TRANSFER : tx_type;
tx.source_asset_type = source_asset;
tx.destination_asset_type = dest_asset;
@@ -849,7 +856,7 @@ namespace cryptonote
uint64_t summary_outs_money = 0;
//fill outputs
size_t output_index = 0;
size_t change_index = 0;
uint8_t change_index = 0;
for(const tx_destination_entry& dst_entr: destinations)
{
CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount);
@@ -891,7 +898,7 @@ namespace cryptonote
need_additional_txkeys, additional_tx_keys,
additional_tx_public_keys, amount_keys, out_eph_public_key,
use_view_tags, view_tag);
tx_out out;
cryptonote::set_tx_out(dst_entr.amount, dst_entr.asset_type, dst_entr.is_change ? 0 : unlock_time, out_eph_public_key, use_view_tags, view_tag, out);
tx.vout.push_back(out);
@@ -902,7 +909,51 @@ namespace cryptonote
remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys));
if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE) {
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && tx.type == cryptonote::transaction_type::TRANSFER) {
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
CHECK_AND_ASSERT_MES(tx.vout.size() >= 2, false, "Internal error - too few outputs for TRANSFER tx");
CHECK_AND_ASSERT_MES(cryptonote::get_output_public_key(tx.vout[change_index], P_change), false, "Internal error - failed to get TX change output public key");
CHECK_AND_ASSERT_MES(P_change != crypto::null_pkey, false, "Internal error - not found TX change output for TRANSFER tx");
// Calculate the F points and change mask for every destination
for (size_t op_index=0; op_index<tx.vout.size(); ++op_index) {
// Calculate the y value for return_payment support
ec_scalar y;
struct {
char domain_separator[8];
rct::key amount_key;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 7);
buf.amount_key = amount_keys[op_index];
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// Now generate the return address (and TX pubkey, although we will discard that)
crypto::public_key F = crypto::null_pkey;
crypto::public_key F_txpubkey = crypto::null_pkey;
CHECK_AND_ASSERT_MES(get_return_address(tx.version, tx.type, y, sender_account_keys, P_change, additional_tx_public_keys[op_index], F, F_txpubkey, hwdev), false, "Failed to get return_address");
// Push the F point into the TX vector of F points
tx.return_address_list.push_back(F);
// Calculate the encrypted_change_index data for this output
struct {
char domain_separator[8];
rct::key amount_key;
} eci_buf;
std::memset(eci_buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(eci_buf.domain_separator, "CHG_IDX", 8);
eci_buf.amount_key = amount_keys[op_index];
crypto::secret_key eci_out;
keccak((uint8_t *)&eci_buf, sizeof(eci_buf), (uint8_t*)&eci_out, sizeof(eci_out));
uint8_t eci_data = change_index ^ eci_out.data[0];
tx.return_address_change_mask.push_back(eci_data);
}
} else if (tx.type == cryptonote::transaction_type::TRANSFER || tx.type == cryptonote::transaction_type::STAKE) {
// Get the output public key for the change output
crypto::public_key P_change = crypto::null_pkey;
@@ -150,6 +150,7 @@ namespace cryptonote
FIELD(original)
VARINT_FIELD(amount)
FIELD(addr)
FIELD(asset_type)
FIELD(is_subaddress)
FIELD(is_integrated)
FIELD(is_change)
+3 -3
View File
@@ -259,10 +259,10 @@ namespace cryptonote
tvc.m_invalid_output = true;
return false;
}
// Check the TX type
if (tx.type <= cryptonote::transaction_type::UNSET || tx.type > cryptonote::transaction_type::MAX) {
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid type " << (uint8_t)tx.type);
if (!m_blockchain.check_tx_type_and_version(tx, tvc)) {
LOG_PRINT_L1("Transaction with id= "<< id << " has invalid type " << (uint8_t)tx.type << " and/or version " << tx.version);
tvc.m_verifivation_failed = true;
return false;
}
@@ -130,7 +130,7 @@ bool ver_rct_non_semantics_simple_cached
// mixring. Future versions of the protocol may differ in this regard, but if this assumptions
// holds true in the future, enable the verification hash by modifying the `untested_tx`
// condition below.
const bool untested_tx = tx.version > 2 || tx.rct_signatures.type > rct::RCTTypeBulletproofPlus;
const bool untested_tx = tx.version > 3 || tx.rct_signatures.type > rct::RCTTypeBulletproofPlus;
VER_ASSERT(!untested_tx, "Unknown TX type. Make sure RCT cache works correctly with this type and then enable it in the code here.");
// Don't cache older (or newer) rctSig types
+2 -2
View File
@@ -45,8 +45,8 @@ const hardfork_t testnet_hard_forks[] = {
// version 1 from the start of the blockchain
{ 1, 1, 0, 1341378000 },
// version 2 starts from block 1000, which is on or around the 23rd of November, 2015. Fork time finalised on 2015-11-20. No fork voting occurs for the v2 fork.
//{ 2, 1000, 0, 1445355000 },
// version 2 starts from block 250
{ 2, 250, 0, 1445355000 },
};
const size_t num_testnet_hard_forks = sizeof(testnet_hard_forks) / sizeof(testnet_hard_forks[0]);
const uint64_t testnet_hard_fork_version_1_till = ((uint64_t)-1);
+12 -5
View File
@@ -7249,7 +7249,7 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_)
// TODO: add locked versions
if (args_.size() < 2)
{
PRINT_USAGE(USAGE_TRANSFER);
PRINT_USAGE(USAGE_LOCKED_TRANSFER);
return true;
}
@@ -8043,10 +8043,17 @@ bool simple_wallet::return_payment(const std::vector<std::string> &args_)
return true;
}
// Verify we have a valid return_address and tx_pubkey
if (td.m_tx.return_address == crypto::null_pkey || td.m_tx.return_pubkey != crypto::null_pkey) {
fail_msg_writer() << tr("invalid return_address/return_pubkey for txid ") << args_[0];
return true;
if (td.m_tx.version >= HF_VERSION_ENABLE_N_OUTS) {
if (td.m_tx.return_address_list.empty() || td.m_tx.return_address_change_mask.empty()) {
fail_msg_writer() << tr("invalid return_address_list for txid ") << args_[0];
return true;
}
} else {
// Verify we have a valid return_address and tx_pubkey
if (td.m_tx.return_address == crypto::null_pkey || td.m_tx.return_pubkey != crypto::null_pkey) {
fail_msg_writer() << tr("invalid return_address/return_pubkey for txid ") << args_[0];
return true;
}
}
// Check that we have the key image information, and that it is usable
+1 -1
View File
@@ -1,5 +1,5 @@
#define DEF_SALVIUM_VERSION_TAG "@VERSIONTAG@"
#define DEF_SALVIUM_VERSION "0.5.2"
#define DEF_SALVIUM_VERSION "0.5.3-rc2"
#define DEF_MONERO_VERSION_TAG "release"
#define DEF_MONERO_VERSION "0.18.3.3"
#define DEF_MONERO_RELEASE_NAME "Zero"
+77 -14
View File
@@ -11298,8 +11298,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
// gather all dust and non-dust outputs of specified subaddress (if any) and below specified threshold (if any)
bool fund_found = false;
for (size_t i = 0; i < m_transfers.size(); ++i)
for (size_t idx = 0; idx < m_transfers_indices[asset_type].size(); idx++)
{
size_t i = m_transfers_indices[asset_type][idx];
const transfer_details& td = m_transfers[i];
if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
{
@@ -11383,24 +11384,86 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_return(std::vector
uint32_t priority = adjust_priority(0);
std::vector<uint8_t> extra; // No need for a TX extra beyond that which will be calculated herein
// To return a payment, we need to know the y value to process the F value
// ...but the y value is calculated differently depending on the original TX
ec_scalar y;
crypto::public_key return_address = null_pkey;
// Get P_change from the TX
crypto::public_key P_change = crypto::null_pkey;
size_t change_index = (td_origin.m_internal_output_index == 0) ? 1 : 0;
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(td_origin.m_tx.vout[change_index], P_change), error::wallet_internal_error, "Failed to identify change output");
uint8_t change_index;
uint32_t hf_version = get_current_hard_fork();
if (hf_version >= HF_VERSION_ENABLE_N_OUTS && td_origin.m_tx.version >= TRANSACTION_VERSION_N_OUTS) {
// Calculate z_i (the shared secret between sender and ourselves for the original TX)
crypto::public_key txkey_pub = null_pkey; // R
const std::vector<crypto::public_key> in_additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td_origin.m_tx);
if (in_additional_tx_pub_keys.size() != 0) {
THROW_WALLET_EXCEPTION_IF(in_additional_tx_pub_keys.size() != td_origin.m_tx.vout.size(),
error::wallet_internal_error,
tr("at create_transactions_return(): incorrect number of additional TX pubkeys in origin TX for return_payment"));
txkey_pub = in_additional_tx_pub_keys[td_origin.m_internal_output_index];
} else {
txkey_pub = get_tx_pub_key_from_extra(td_origin.m_tx);
}
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
THROW_WALLET_EXCEPTION_IF(!generate_key_derivation(txkey_pub, m_account.get_keys().m_view_secret_key, derivation),
error::wallet_internal_error,
tr("at create_transactions_return(): failed to generate_key_derivation"));
crypto::secret_key z_i;
derivation_to_scalar(derivation, td_origin.m_internal_output_index, z_i);
// Calculate the y value for return_payment support
struct {
char domain_separator[8];
rct::key amount_key;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 7);
buf.amount_key = rct::sk2rct(z_i);
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// The change_index needs decoding too
uint8_t eci_data = td_origin.m_tx.return_address_change_mask[td_origin.m_internal_output_index];
// Calculate the encrypted_change_index data for this output
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "CHG_IDX", 8);
crypto::secret_key eci_out;
keccak((uint8_t *)&buf, sizeof(buf), (uint8_t*)&eci_out, sizeof(eci_out));
change_index = eci_data ^ eci_out.data[0];
return_address = td_origin.m_tx.return_address_list[td_origin.m_internal_output_index];
} else {
// Calculate y
struct {
char domain_separator[8];
crypto::public_key pubkey;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 6);
buf.pubkey = P_change;
crypto::hash_to_scalar(&buf, sizeof(buf), y);
// Change index is the one we didn't receive
change_index = (td_origin.m_internal_output_index == 0) ? 1 : 0;
return_address = td_origin.m_tx.return_address;
}
// Sanity check that we aren't attempting to return our own TX change output to ourselves
THROW_WALLET_EXCEPTION_IF(change_index == td_origin.m_internal_output_index, error::wallet_internal_error, tr("Attempting to return change to ourself"));
// Sanity check that we can obtain the change output from the origin TX
THROW_WALLET_EXCEPTION_IF(!cryptonote::get_output_public_key(td_origin.m_tx.vout[change_index], P_change),
error::wallet_internal_error,
tr("Failed to identify change output"));
// Calculate yF
ec_scalar y;
struct {
char domain_separator[8];
crypto::public_key pubkey;
} buf;
std::memset(buf.domain_separator, 0x0, sizeof(buf.domain_separator));
std::strncpy(buf.domain_separator, "RETURN", 6);
buf.pubkey = P_change;
crypto::hash_to_scalar(&buf, sizeof(buf), y);
rct::key key_y = (rct::key&)(y);
rct::key key_F = (rct::key&)(td_origin.m_tx.return_address);
rct::key key_F = (rct::key&)(return_address);
rct::key key_yF = rct::scalarmultKey(key_F, key_y);
// Build the subaddress to send the return to
+2
View File
@@ -392,6 +392,7 @@ namespace tools
td.address = d.address(m_wallet->nettype(), pd.m_payment_id);
}
entry.asset_type = pd.m_tx.source_asset_type;
entry.type = "out";
entry.subaddr_index = { pd.m_subaddr_account, 0 };
for (uint32_t i: pd.m_subaddr_indices)
@@ -424,6 +425,7 @@ namespace tools
}
entry.type = is_failed ? "failed" : "pending";
entry.asset_type = pd.m_tx.source_asset_type;
entry.subaddr_index = { pd.m_subaddr_account, 0 };
for (uint32_t i: pd.m_subaddr_indices)
entry.subaddr_indices.push_back({pd.m_subaddr_account, i});