2022-10-22 21:00:14 +02:00
// Copyright (c) 2014-2022 Zano Project
2018-12-27 18:50:45 +03:00
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include "chaingen.h"
# include "pos_block_builder.h"
2022-05-11 21:23:44 +02:00
using namespace epee ;
2018-12-27 18:50:45 +03:00
using namespace currency ;
void pos_block_builder : : clear ( )
{
2022-10-23 02:50:30 +02:00
* this = pos_block_builder { } ;
2018-12-27 18:50:45 +03:00
}
2022-10-24 21:01:45 +02:00
2022-10-22 21:00:14 +02:00
void pos_block_builder : : step1_init_header ( const hard_forks_descriptor & hardforks , size_t block_height , crypto : : hash & prev_block_hash )
2018-12-27 18:50:45 +03:00
{
CHECK_AND_ASSERT_THROW_MES ( m_step = = 0 , " pos_block_builder: incorrect step sequence " ) ;
m_block . minor_version = CURRENT_BLOCK_MINOR_VERSION ;
2022-10-22 21:00:14 +02:00
m_block . major_version = hardforks . get_block_major_version_by_height ( block_height ) ;
2018-12-27 18:50:45 +03:00
m_block . timestamp = 0 ; // to be set at step 3
m_block . prev_id = prev_block_hash ;
m_block . flags = CURRENCY_BLOCK_FLAG_POS_BLOCK ;
m_block . nonce = 0 ;
m_height = block_height ;
2022-10-24 21:01:45 +02:00
m_context . zarcanum = hardforks . is_hardfork_active_for_height ( ZANO_HARDFORK_04_ZARCANUM , m_height ) ;
2018-12-27 18:50:45 +03:00
m_step = 1 ;
}
2022-10-24 21:01:45 +02:00
2018-12-27 18:50:45 +03:00
void pos_block_builder : : step2_set_txs ( const std : : vector < currency : : transaction > & txs )
{
CHECK_AND_ASSERT_THROW_MES ( m_step = = 1 , " pos_block_builder: incorrect step sequence " ) ;
m_total_fee = 0 ;
m_txs_total_size = 0 ;
m_block . tx_hashes . reserve ( txs . size ( ) ) ;
for ( auto & tx : txs )
{
uint64_t fee = 0 ;
bool r = get_tx_fee ( tx , fee ) ;
CHECK_AND_ASSERT_THROW_MES ( r , " wrong transaction passed to step2_set_txs " ) ;
m_total_fee + = fee ;
m_txs_total_size + = get_object_blobsize ( tx ) ;
m_block . tx_hashes . push_back ( get_transaction_hash ( tx ) ) ;
}
m_step = 2 ;
}
2022-10-24 21:01:45 +02:00
2018-12-27 18:50:45 +03:00
void pos_block_builder : : step3_build_stake_kernel (
uint64_t stake_output_amount ,
size_t stake_output_gindex ,
const crypto : : key_image & stake_output_key_image ,
currency : : wide_difficulty_type difficulty ,
const crypto : : hash & last_pow_block_hash ,
const crypto : : hash & last_pos_block_kernel_hash ,
uint64_t timestamp_lower_bound ,
uint64_t timestamp_window ,
uint64_t timestamp_step )
2022-10-24 21:01:45 +02:00
{
step3a ( difficulty , last_pow_block_hash , last_pos_block_kernel_hash ) ;
crypto : : public_key stake_source_tx_pub_key { } ;
uint64_t stake_out_in_tx_index = UINT64_MAX ;
crypto : : scalar_t stake_out_blinding_mask { } ;
crypto : : secret_key view_secret { } ;
step3b ( stake_output_amount , stake_output_key_image , stake_source_tx_pub_key , stake_out_in_tx_index , stake_out_blinding_mask , view_secret , stake_output_gindex ,
timestamp_lower_bound , timestamp_window , timestamp_step ) ;
}
void pos_block_builder : : step3a (
currency : : wide_difficulty_type difficulty ,
const crypto : : hash & last_pow_block_hash ,
const crypto : : hash & last_pos_block_kernel_hash
)
2018-12-27 18:50:45 +03:00
{
CHECK_AND_ASSERT_THROW_MES ( m_step = = 2 , " pos_block_builder: incorrect step sequence " ) ;
2022-10-24 21:01:45 +02:00
stake_modifier_type sm { } ;
sm . last_pow_id = last_pow_block_hash ;
sm . last_pos_kernel_id = last_pos_block_kernel_hash ;
2018-12-27 18:50:45 +03:00
if ( last_pos_block_kernel_hash = = null_hash )
{
2022-10-24 21:01:45 +02:00
bool r = string_tools : : parse_tpod_from_hex_string ( POS_STARTER_KERNEL_HASH , sm . last_pos_kernel_id ) ;
2019-09-07 12:46:25 +03:00
CHECK_AND_ASSERT_THROW_MES ( r , " Failed to parse POS_STARTER_KERNEL_HASH " ) ;
2018-12-27 18:50:45 +03:00
}
2022-10-24 21:01:45 +02:00
m_context . init ( difficulty , sm , m_context . zarcanum ) ;
m_step = 31 ;
}
void pos_block_builder : : step3b (
uint64_t stake_output_amount ,
const crypto : : key_image & stake_output_key_image ,
const crypto : : public_key & stake_source_tx_pub_key , // zarcanum only
uint64_t stake_out_in_tx_index , // zarcanum only
const crypto : : scalar_t & stake_out_blinding_mask , // zarcanum only
const crypto : : secret_key & view_secret , // zarcanum only
size_t stake_output_gindex ,
uint64_t timestamp_lower_bound ,
uint64_t timestamp_window ,
uint64_t timestamp_step )
{
CHECK_AND_ASSERT_THROW_MES ( m_step = = 31 , " pos_block_builder: incorrect step sequence " ) ;
m_pos_stake_output_gindex = stake_output_gindex ;
m_context . prepare_entry ( stake_output_amount , stake_output_key_image , stake_source_tx_pub_key , stake_out_in_tx_index , stake_out_blinding_mask , view_secret ) ;
2018-12-27 18:50:45 +03:00
// align timestamp_lower_bound up to timestamp_step boundary if needed
if ( timestamp_lower_bound % timestamp_step ! = 0 )
timestamp_lower_bound = timestamp_lower_bound - ( timestamp_lower_bound % timestamp_step ) + timestamp_step ;
bool sk_found = false ;
for ( uint64_t ts = timestamp_lower_bound ; ! sk_found & & ts < timestamp_lower_bound + timestamp_window ; ts + = timestamp_step )
{
2022-10-24 21:01:45 +02:00
if ( m_context . do_iteration ( ts ) )
2018-12-27 18:50:45 +03:00
sk_found = true ;
}
if ( ! sk_found )
ASSERT_MES_AND_THROW ( " Could't build stake kernel " ) ;
// update block header with found timestamp
2022-10-24 21:01:45 +02:00
m_block . timestamp = m_context . sk . block_timestamp ;
2018-12-27 18:50:45 +03:00
m_step = 3 ;
}
2022-10-24 21:01:45 +02:00
2019-09-06 18:59:02 +03:00
void pos_block_builder : : step4_generate_coinbase_tx ( size_t median_size ,
const boost : : multiprecision : : uint128_t & already_generated_coins ,
const account_public_address & reward_and_stake_receiver_address ,
const blobdata & extra_nonce ,
size_t max_outs ,
2022-11-08 00:07:53 +01:00
const keypair * tx_one_time_key_to_use )
2019-09-06 18:59:02 +03:00
{
2022-11-08 00:07:53 +01:00
step4_generate_coinbase_tx ( median_size , already_generated_coins , reward_and_stake_receiver_address , reward_and_stake_receiver_address , extra_nonce , max_outs , tx_one_time_key_to_use ) ;
2019-09-06 18:59:02 +03:00
}
2022-10-24 21:01:45 +02:00
2018-12-27 18:50:45 +03:00
void pos_block_builder : : step4_generate_coinbase_tx ( size_t median_size ,
2019-04-10 03:00:29 +02:00
const boost : : multiprecision : : uint128_t & already_generated_coins ,
2018-12-27 18:50:45 +03:00
const account_public_address & reward_receiver_address ,
2019-09-06 18:59:02 +03:00
const account_public_address & stakeholder_address ,
2018-12-27 18:50:45 +03:00
const blobdata & extra_nonce ,
size_t max_outs ,
2022-11-08 00:07:53 +01:00
const keypair * tx_one_time_key_to_use )
2018-12-27 18:50:45 +03:00
{
CHECK_AND_ASSERT_THROW_MES ( m_step = = 3 , " pos_block_builder: incorrect step sequence " ) ;
2022-11-08 00:07:53 +01:00
uint64_t tx_version = m_context . zarcanum ? TRANSACTION_VERSION_POST_HF4 : TRANSACTION_VERSION_PRE_HF4 ;
pos_entry pe { } ;
pe . stake_unlock_time = 0 ; // TODO
pe . amount = m_context . stake_amount ;
2018-12-27 18:50:45 +03:00
// generate miner tx using incorrect current_block_size only for size estimation
size_t estimated_block_size = m_txs_total_size ;
2022-11-08 00:07:53 +01:00
bool r = construct_miner_tx ( m_height , median_size , already_generated_coins , estimated_block_size , m_total_fee ,
reward_receiver_address , stakeholder_address , m_block . miner_tx , tx_version , extra_nonce , max_outs , true , pe , & m_blinding_masks_sum , tx_one_time_key_to_use ) ;
CHECK_AND_ASSERT_THROW_MES ( r , " construct_miner_tx failed " ) ;
2018-12-27 18:50:45 +03:00
estimated_block_size = m_txs_total_size + get_object_blobsize ( m_block . miner_tx ) ;
size_t cumulative_size = 0 ;
for ( size_t try_count = 0 ; try_count ! = 10 ; + + try_count )
{
2022-11-08 00:07:53 +01:00
r = construct_miner_tx ( m_height , median_size , already_generated_coins , estimated_block_size , m_total_fee ,
reward_receiver_address , stakeholder_address , m_block . miner_tx , tx_version , extra_nonce , max_outs , true , pe , & m_blinding_masks_sum , tx_one_time_key_to_use ) ;
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_THROW_MES ( r , " construct_homemade_pos_miner_tx failed " ) ;
cumulative_size = m_txs_total_size + get_object_blobsize ( m_block . miner_tx ) ;
if ( cumulative_size = = estimated_block_size )
break ; // nice, got what we want
if ( cumulative_size > estimated_block_size )
{
estimated_block_size = cumulative_size ;
continue ; // one more attempt
}
// TODO: implement this rare case
ASSERT_MES_AND_THROW ( " step4_generate_coinbase_tx implement todo " ) ;
}
CHECK_AND_ASSERT_THROW_MES ( cumulative_size = = estimated_block_size , " step4_generate_coinbase_tx failed to match tx and block size " ) ;
m_step = 4 ;
}
2022-10-24 21:01:45 +02:00
2022-11-08 00:07:53 +01:00
void pos_block_builder : : step5_sign ( const currency : : tx_source_entry & se , const currency : : account_keys & stakeholder_keys )
2018-12-27 18:50:45 +03:00
{
2022-11-08 00:07:53 +01:00
bool r = false ;
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_THROW_MES ( m_step = = 4 , " pos_block_builder: incorrect step sequence " ) ;
2022-11-08 00:07:53 +01:00
// calculate stake_out_derivation and secret_x (derived ephemeral secret key)
crypto : : key_derivation stake_out_derivation = AUTO_VAL_INIT ( stake_out_derivation ) ;
r = crypto : : generate_key_derivation ( se . real_out_tx_key , stakeholder_keys . view_secret_key , stake_out_derivation ) ; // d = 8 * v * R
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_THROW_MES ( r , " generate_key_derivation failed " ) ;
2022-10-25 04:16:25 +02:00
crypto : : secret_key secret_x = AUTO_VAL_INIT ( secret_x ) ;
2022-11-08 00:07:53 +01:00
crypto : : derive_secret_key ( stake_out_derivation , se . real_output_in_tx_index , stakeholder_keys . spend_secret_key , secret_x ) ; // x = Hs(8 * v * R, i) + s
if ( m_context . zarcanum )
{
// Zarcanum
zarcanum_sig & sig = boost : : get < zarcanum_sig > ( m_block . miner_tx . signatures [ 0 ] ) ;
txin_zc_input & stake_input = boost : : get < txin_zc_input > ( m_block . miner_tx . vin [ 1 ] ) ;
stake_input . k_image = m_context . sk . kimage ;
for ( const auto & oe : se . outputs )
{
//oe.
}
2018-12-27 18:50:45 +03:00
2022-11-08 00:07:53 +01:00
stake_input . key_offsets . push_back ( m_pos_stake_output_gindex ) ; // TODO: support decoys
crypto : : hash tx_hash_for_sig = get_transaction_hash ( m_block . miner_tx ) ; // TODO @#@# change to block hash after the corresponding test is made
std : : vector < crypto : : CLSAG_GGXG_input_ref_t > ring ;
uint64_t secret_index = 0 ; // index of the real stake output
uint8_t err = 0 ;
r = crypto : : zarcanum_generate_proof ( tx_hash_for_sig , m_context . kernel_hash , ring , m_context . last_pow_block_id_hashed , m_context . sk . kimage ,
secret_x , m_context . secret_q , secret_index , m_blinding_masks_sum , m_context . stake_amount , m_context . stake_out_blinding_mask ,
static_cast < crypto : : zarcanum_proof & > ( sig ) , & err ) ;
CHECK_AND_ASSERT_THROW_MES ( r , " zarcanum_generate_proof failed, err: " < < ( int ) err ) ;
}
else
{
// old PoS with non-hidden amounts
NLSAG_sig & sig = boost : : get < NLSAG_sig > ( m_block . miner_tx . signatures [ 0 ] ) ;
txin_to_key & stake_input = boost : : get < txin_to_key > ( m_block . miner_tx . vin [ 1 ] ) ;
stake_input . k_image = m_context . sk . kimage ;
stake_input . amount = m_context . stake_amount ;
stake_input . key_offsets . push_back ( m_pos_stake_output_gindex ) ;
crypto : : hash block_hash = currency : : get_block_hash ( m_block ) ;
std : : vector < const crypto : : public_key * > keys_ptrs ( 1 , & se . outputs . front ( ) . stealth_address ) ;
sig . s . resize ( 1 ) ;
crypto : : generate_ring_signature ( block_hash , m_context . sk . kimage , keys_ptrs , secret_x , 0 , sig . s . data ( ) ) ;
}
2018-12-27 18:50:45 +03:00
m_step = 5 ;
}
2022-10-24 21:01:45 +02:00
2022-11-08 00:07:53 +01:00
void pos_block_builder : : step5_sign ( const crypto : : public_key & stake_tx_pub_key , size_t stake_tx_out_index , const crypto : : public_key & stake_tx_out_pub_key ,
const currency : : account_base & stakeholder_account )
{
bool r = false ;
CHECK_AND_ASSERT_THROW_MES ( m_step = = 4 , " pos_block_builder: incorrect step sequence " ) ;
// calculate stake_out_derivation and secret_x (derived ephemeral secret key)
crypto : : key_derivation stake_out_derivation = AUTO_VAL_INIT ( stake_out_derivation ) ;
r = crypto : : generate_key_derivation ( stake_tx_pub_key , stakeholder_account . get_keys ( ) . view_secret_key , stake_out_derivation ) ; // d = 8 * v * R
CHECK_AND_ASSERT_THROW_MES ( r , " generate_key_derivation failed " ) ;
crypto : : secret_key secret_x = AUTO_VAL_INIT ( secret_x ) ;
crypto : : derive_secret_key ( stake_out_derivation , stake_tx_out_index , stakeholder_account . get_keys ( ) . spend_secret_key , secret_x ) ; // x = Hs(8 * v * R, i) + s
if ( m_context . zarcanum )
{
// Zarcanum
zarcanum_sig & sig = boost : : get < zarcanum_sig > ( m_block . miner_tx . signatures [ 0 ] ) ;
txin_zc_input & stake_input = boost : : get < txin_zc_input > ( m_block . miner_tx . vin [ 1 ] ) ;
stake_input . k_image = m_context . sk . kimage ;
stake_input . key_offsets . push_back ( m_pos_stake_output_gindex ) ; // TODO: support decoys
crypto : : hash tx_hash_for_sig = get_transaction_hash ( m_block . miner_tx ) ; // TODO @#@# change to block hash after the corresponding test is made
std : : vector < crypto : : CLSAG_GGXG_input_ref_t > ring ;
uint64_t secret_index = 0 ; // index of the real stake output
uint8_t err = 0 ;
r = crypto : : zarcanum_generate_proof ( tx_hash_for_sig , m_context . kernel_hash , ring , m_context . last_pow_block_id_hashed , m_context . sk . kimage ,
secret_x , m_context . secret_q , secret_index , m_blinding_masks_sum , m_context . stake_amount , m_context . stake_out_blinding_mask ,
static_cast < crypto : : zarcanum_proof & > ( sig ) , & err ) ;
CHECK_AND_ASSERT_THROW_MES ( r , " zarcanum_generate_proof failed, err: " < < ( int ) err ) ;
}
else
{
// old PoS with non-hidden amounts
NLSAG_sig & sig = boost : : get < NLSAG_sig > ( m_block . miner_tx . signatures [ 0 ] ) ;
txin_to_key & stake_input = boost : : get < txin_to_key > ( m_block . miner_tx . vin [ 1 ] ) ;
stake_input . k_image = m_context . sk . kimage ;
stake_input . amount = m_context . stake_amount ;
stake_input . key_offsets . push_back ( m_pos_stake_output_gindex ) ;
crypto : : hash block_hash = currency : : get_block_hash ( m_block ) ;
std : : vector < const crypto : : public_key * > keys_ptrs ( 1 , & stake_tx_out_pub_key ) ;
sig . s . resize ( 1 ) ;
crypto : : generate_ring_signature ( block_hash , m_context . sk . kimage , keys_ptrs , secret_x , 0 , sig . s . data ( ) ) ;
}
m_step = 5 ;
}
/*
2022-10-25 04:16:25 +02:00
void pos_block_builder : : step5_sign_zarcanum ( const crypto : : public_key & stake_tx_pub_key , size_t stake_tx_out_index , const currency : : account_base & stakeholder_account )
{
CHECK_AND_ASSERT_THROW_MES ( m_step = = 4 , " pos_block_builder: incorrect step sequence " ) ;
CHECK_AND_ASSERT_THROW_MES ( m_block . miner_tx . signatures . size ( ) = = 1 , " pos_block_builder: incorrect size of miner_tx signatures: " < < m_block . miner_tx . signatures . size ( ) ) ;
zarcanum_sig & sig = boost : : get < zarcanum_sig > ( m_block . miner_tx . signatures [ 0 ] ) ;
crypto : : key_derivation pos_coin_derivation { } ;
bool r = crypto : : generate_key_derivation ( stake_tx_pub_key , stakeholder_account . get_keys ( ) . view_secret_key , pos_coin_derivation ) ; // v * 8 * R
CHECK_AND_ASSERT_THROW_MES ( r , " generate_key_derivation failed " ) ;
crypto : : secret_key secret_x { } ;
crypto : : derive_secret_key ( pos_coin_derivation , stake_tx_out_index , stakeholder_account . get_keys ( ) . spend_secret_key , secret_x ) ; // x = s + Hs(v * 8 * R, i)
std : : vector < crypto : : CLSAG_GGXG_input_ref_t > ring ;
uint64_t secret_index = 0 ;
2022-10-25 23:59:25 +02:00
crypto : : scalar_t blinding_masks_sum ;
2022-10-25 04:16:25 +02:00
crypto : : hash tx_hash_for_sig = get_transaction_hash ( m_block . miner_tx ) ; // TODO @#@# change to currency::get_block_hash(m_block);
uint8_t err = 0 ;
r = crypto : : zarcanum_generate_proof ( tx_hash_for_sig , m_context . kernel_hash , ring , m_context . last_pow_block_id_hashed , m_context . sk . kimage ,
secret_x , m_context . secret_q , secret_index , blinding_masks_sum , m_context . stake_amount , m_context . stake_out_blinding_mask ,
static_cast < crypto : : zarcanum_proof & > ( sig ) , & err ) ;
CHECK_AND_ASSERT_THROW_MES ( r , " zarcanum_generate_proof failed, err: " < < ( int ) err ) ;
m_step = 5 ;
}
2022-11-08 00:07:53 +01:00
*/
2022-10-25 04:16:25 +02:00
2022-11-08 00:07:53 +01:00
/*
bool construct_homemade_pos_miner_tx ( bool zarcanum , size_t height , size_t median_size , const boost : : multiprecision : : uint128_t & already_generated_coins ,
2018-12-27 18:50:45 +03:00
size_t current_block_size ,
uint64_t fee ,
uint64_t pos_stake_amount ,
crypto : : key_image pos_stake_keyimage ,
size_t pos_stake_gindex ,
2019-09-06 18:59:02 +03:00
const account_public_address & reward_receiving_address ,
const account_public_address & stakeholder_address ,
2018-12-27 18:50:45 +03:00
transaction & tx ,
2022-11-08 00:07:53 +01:00
const blobdata & extra_nonce , //= blobdata(),
size_t max_outs , //= CURRENCY_MINER_TX_MAX_OUTS,
keypair tx_one_time_key , //= keypair::generate())
2018-12-27 18:50:45 +03:00
{
2022-11-08 00:07:53 +01:00
tx = transaction { } ;
2018-12-27 18:50:45 +03:00
2022-11-08 00:07:53 +01:00
tx . version = zarcanum ? TRANSACTION_VERSION_POST_HF4 : TRANSACTION_VERSION_PRE_HF4 ;
2018-12-27 18:50:45 +03:00
set_tx_unlock_time ( tx , height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW ) ;
// calculate block reward
uint64_t block_reward ;
bool r = get_block_reward ( true , median_size , current_block_size , already_generated_coins , block_reward , height ) ;
2022-11-08 00:07:53 +01:00
CHECK_AND_ASSERT_MES ( r , false , " get_block_reward failed " ) ;
2018-12-27 18:50:45 +03:00
block_reward + = fee ;
2022-11-08 00:07:53 +01:00
//
// prepare destinations
//
// 1. split block_reward into out_amounts
2018-12-27 18:50:45 +03:00
std : : vector < size_t > out_amounts ;
2022-11-08 00:07:53 +01:00
if ( tx . version > TRANSACTION_VERSION_PRE_HF4 )
2018-12-27 18:50:45 +03:00
{
2022-11-08 00:07:53 +01:00
// randomly split into CURRENCY_TX_MIN_ALLOWED_OUTS outputs
decompose_amount_randomly ( block_reward , [ & ] ( uint64_t a ) { out_amounts . push_back ( a ) ; } , CURRENCY_TX_MIN_ALLOWED_OUTS ) ;
}
else
{
// non-hidden outs: split into digits
decompose_amount_into_digits ( block_reward , DEFAULT_DUST_THRESHOLD ,
[ & out_amounts ] ( uint64_t a_chunk ) { out_amounts . push_back ( a_chunk ) ; } ,
[ & out_amounts ] ( uint64_t a_dust ) { out_amounts . push_back ( a_dust ) ; } ) ;
CHECK_AND_ASSERT_MES ( 1 < = max_outs , false , " max_out must be non-zero " ) ;
while ( max_outs < out_amounts . size ( ) )
{
out_amounts [ out_amounts . size ( ) - 2 ] + = out_amounts . back ( ) ;
out_amounts . resize ( out_amounts . size ( ) - 1 ) ;
}
2018-12-27 18:50:45 +03:00
}
2019-09-06 18:59:02 +03:00
// reward
2020-04-23 15:41:40 +03:00
bool burn_money = reward_receiving_address . spend_public_key = = null_pkey & & reward_receiving_address . view_public_key = = null_pkey ; // if true, burn reward, so no one on Earth can spend them
2018-12-27 18:50:45 +03:00
for ( size_t output_index = 0 ; output_index < out_amounts . size ( ) ; + + output_index )
{
txout_to_key tk ;
tk . key = null_pkey ; // null means burn money
tk . mix_attr = 0 ;
if ( ! burn_money )
{
2019-09-06 18:59:02 +03:00
r = currency : : derive_public_key_from_target_address ( reward_receiving_address , tx_one_time_key . sec , output_index , tk . key ) ; // derivation(view_pub; tx_sec).derive(output_index, spend_pub) => output pub key
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES ( r , false , " failed to derive_public_key_from_target_address " ) ;
}
2022-05-17 17:32:53 +02:00
tx_out_bare out ;
2018-12-27 18:50:45 +03:00
out . amount = out_amounts [ output_index ] ;
out . target = tk ;
tx . vout . push_back ( out ) ;
}
2019-09-06 18:59:02 +03:00
// stake
2020-04-23 15:41:40 +03:00
burn_money = stakeholder_address . spend_public_key = = null_pkey & & stakeholder_address . view_public_key = = null_pkey ; // if true, burn stake
2018-12-27 18:50:45 +03:00
{
2019-09-06 18:59:02 +03:00
txout_to_key tk ;
tk . key = null_pkey ; // null means burn money
tk . mix_attr = 0 ;
if ( ! burn_money )
2018-12-27 18:50:45 +03:00
{
2019-09-06 18:59:02 +03:00
r = currency : : derive_public_key_from_target_address ( stakeholder_address , tx_one_time_key . sec , tx . vout . size ( ) , tk . key ) ;
CHECK_AND_ASSERT_MES ( r , false , " failed to derive_public_key_from_target_address " ) ;
2018-12-27 18:50:45 +03:00
}
2019-09-06 18:59:02 +03:00
2022-05-17 17:32:53 +02:00
tx_out_bare out ;
2019-09-06 18:59:02 +03:00
out . amount = pos_stake_amount ;
out . target = tk ;
tx . vout . push_back ( out ) ;
2018-12-27 18:50:45 +03:00
}
2019-09-06 18:59:02 +03:00
// take care about extra
add_tx_pub_key_to_extra ( tx , tx_one_time_key . pub ) ;
if ( extra_nonce . size ( ) )
if ( ! add_tx_extra_userdata ( tx , extra_nonce ) )
return false ;
2018-12-27 18:50:45 +03:00
// populate ins with 1) money-generating and 2) PoS
txin_gen in ;
in . height = height ;
tx . vin . push_back ( in ) ;
txin_to_key posin ;
posin . amount = pos_stake_amount ;
posin . key_offsets . push_back ( pos_stake_gindex ) ;
posin . k_image = pos_stake_keyimage ;
tx . vin . push_back ( posin ) ;
//reserve place for ring signature
2022-06-19 19:47:43 +02:00
tx . signatures . resize ( 1 ) ;
boost : : get < currency : : NLSAG_sig > ( tx . signatures [ 0 ] ) . s . resize ( posin . key_offsets . size ( ) ) ;
2018-12-27 18:50:45 +03:00
return true ;
}
2022-11-08 00:06:52 +01:00
*/
2018-12-27 18:50:45 +03:00
2022-10-24 21:01:45 +02:00
2018-12-27 18:50:45 +03:00
bool mine_next_pos_block_in_playtime_sign_cb ( currency : : core & c , const currency : : block & prev_block , const currency : : block & coinstake_scr_block , const currency : : account_base & acc ,
std : : function < bool ( currency : : block & ) > before_sign_cb , currency : : block & output )
{
2022-10-22 21:00:14 +02:00
blockchain_storage & bcs = c . get_blockchain_storage ( ) ;
2018-12-27 18:50:45 +03:00
// these values (median and diff) are correct only for the next main chain block, it's incorrect for altblocks, especially for old altblocks
// but for now we assume they will work fine
2022-10-22 21:00:14 +02:00
uint64_t block_size_median = bcs . get_current_comulative_blocksize_limit ( ) / 2 ;
currency : : wide_difficulty_type difficulty = bcs . get_next_diff_conditional ( true ) ;
2018-12-27 18:50:45 +03:00
crypto : : hash prev_id = get_block_hash ( prev_block ) ;
size_t height = get_block_height ( prev_block ) + 1 ;
block_extended_info bei = AUTO_VAL_INIT ( bei ) ;
2022-10-22 21:00:14 +02:00
bool r = bcs . get_block_extended_info_by_hash ( prev_id , bei ) ;
2018-12-27 18:50:45 +03:00
CHECK_AND_ASSERT_MES ( r , false , " get_block_extended_info_by_hash failed for hash = " < < prev_id ) ;
const transaction & stake = coinstake_scr_block . miner_tx ;
crypto : : public_key stake_tx_pub_key = get_tx_pub_key_from_extra ( stake ) ;
size_t stake_output_idx = 0 ;
size_t stake_output_gidx = 0 ;
2022-05-20 21:32:27 +02:00
uint64_t stake_output_amount = boost : : get < currency : : tx_out_bare > ( stake . vout [ stake_output_idx ] ) . amount ;
2018-12-27 18:50:45 +03:00
crypto : : key_image stake_output_key_image ;
keypair kp ;
generate_key_image_helper ( acc . get_keys ( ) , stake_tx_pub_key , stake_output_idx , kp , stake_output_key_image ) ;
2022-05-20 21:32:27 +02:00
crypto : : public_key stake_output_pubkey = boost : : get < txout_to_key > ( boost : : get < currency : : tx_out_bare > ( stake . vout [ stake_output_idx ] ) . target ) . key ;
2018-12-27 18:50:45 +03:00
pos_block_builder pb ;
2022-10-22 21:00:14 +02:00
pb . step1_init_header ( bcs . get_core_runtime_config ( ) . hard_forks , height , prev_id ) ;
2018-12-27 18:50:45 +03:00
pb . step2_set_txs ( std : : vector < transaction > ( ) ) ;
pb . step3_build_stake_kernel ( stake_output_amount , stake_output_gidx , stake_output_key_image , difficulty , prev_id , null_hash , prev_block . timestamp ) ;
pb . step4_generate_coinbase_tx ( block_size_median , bei . already_generated_coins , acc . get_public_address ( ) ) ;
if ( ! before_sign_cb ( pb . m_block ) )
return false ;
pb . step5_sign ( stake_tx_pub_key , stake_output_idx , stake_output_pubkey , acc ) ;
output = pb . m_block ;
return true ;
}