network mapping fix
This commit is contained in:
parent
0e852e0e69
commit
9cc17ac0b5
|
|
@ -1,9 +1,6 @@
|
||||||
use crate::blocks::rewards::{RewardsTransaction, UnsignedRewardsTransaction};
|
use crate::blocks::rewards::{RewardsTransaction, UnsignedRewardsTransaction};
|
||||||
use crate::common::types::BLOCKS_PER_HALVING;
|
use crate::common::types::BLOCKS_PER_HALVING;
|
||||||
use crate::records::block_height::get_block_height::get_height;
|
|
||||||
use crate::records::memory::chain_state::cached_chain_height;
|
|
||||||
use crate::records::memory::network_mapping::NodeInfo;
|
use crate::records::memory::network_mapping::NodeInfo;
|
||||||
use crate::sled::Db;
|
|
||||||
|
|
||||||
const REWARD_MATURITY_BLOCKS: u8 = 100;
|
const REWARD_MATURITY_BLOCKS: u8 = 100;
|
||||||
|
|
||||||
|
|
@ -26,29 +23,22 @@ pub async fn calculate_block_reward(block_height: u32) -> u64 {
|
||||||
reward
|
reward
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_rewards_transaction(
|
pub async fn reward_value_for_miner_at_height(short_address: &str, block_height: u32) -> u64 {
|
||||||
short_address: &str,
|
// New miners must first prove participation before receiving the
|
||||||
timestamp: u32,
|
// block subsidy. The mined count is maintained in the network map and
|
||||||
db: &Db,
|
// rebuilt from headers only during startup/recovery/reorg correction.
|
||||||
) -> RewardsTransaction {
|
if NodeInfo::get_mined_count(short_address).await < REWARD_MATURITY_BLOCKS {
|
||||||
|
return 0_u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
calculate_block_reward(block_height).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_rewards_transaction(timestamp: u32, value: u64) -> RewardsTransaction {
|
||||||
// Rewards are created as the first transaction in every
|
// Rewards are created as the first transaction in every
|
||||||
// mined block using the current reward schedule.
|
// mined block using the current reward schedule.
|
||||||
let txtype = 1;
|
let txtype = 1;
|
||||||
|
|
||||||
// The reward belongs to the block being created, not the current tip.
|
|
||||||
let block_height = cached_chain_height()
|
|
||||||
.await
|
|
||||||
.unwrap_or_else(|| get_height(db))
|
|
||||||
+ 1;
|
|
||||||
|
|
||||||
// New miners must first prove participation before receiving
|
|
||||||
// the block subsidy, so early mined blocks pay a zero reward.
|
|
||||||
let value = if NodeInfo::get_mined_count(short_address).await < REWARD_MATURITY_BLOCKS {
|
|
||||||
0_u64
|
|
||||||
} else {
|
|
||||||
calculate_block_reward(block_height).await
|
|
||||||
};
|
|
||||||
|
|
||||||
// Reward transactions are unsigned because they are created by
|
// Reward transactions are unsigned because they are created by
|
||||||
// consensus rules rather than by a wallet spending funds.
|
// consensus rules rather than by a wallet spending funds.
|
||||||
let unsigned_rewards = UnsignedRewardsTransaction::new(txtype, timestamp, value).await;
|
let unsigned_rewards = UnsignedRewardsTransaction::new(txtype, timestamp, value).await;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::blocks::block::{Block, UnminedBlock};
|
use crate::blocks::block::{Block, UnminedBlock};
|
||||||
use crate::common::types::Transaction;
|
use crate::common::types::Transaction;
|
||||||
use crate::log::{error, info};
|
use crate::log::{error, info};
|
||||||
use crate::miner::block_rewards::create_rewards_transaction;
|
use crate::miner::block_rewards::{create_rewards_transaction, reward_value_for_miner_at_height};
|
||||||
use crate::miner::fairness::wait_for_fairness_gate;
|
use crate::miner::fairness::wait_for_fairness_gate;
|
||||||
use crate::miner::flag::{is_mining_stop_requested, is_normal_mode, set_mining_state, MiningState};
|
use crate::miner::flag::{is_mining_stop_requested, is_normal_mode, set_mining_state, MiningState};
|
||||||
use crate::miner::nonce::run_nonce_round;
|
use crate::miner::nonce::run_nonce_round;
|
||||||
|
|
@ -229,6 +229,7 @@ async fn build_attempt_context(
|
||||||
};
|
};
|
||||||
let previous_hash = previous_block.hash().await;
|
let previous_hash = previous_block.hash().await;
|
||||||
let previous_difficulty = previous_block.unmined_block.next_block_difficulty;
|
let previous_difficulty = previous_block.unmined_block.next_block_difficulty;
|
||||||
|
let reward_value = reward_value_for_miner_at_height(&miner_short, current_block_number).await;
|
||||||
|
|
||||||
Ok(MiningAttemptContext {
|
Ok(MiningAttemptContext {
|
||||||
db: db.clone(),
|
db: db.clone(),
|
||||||
|
|
@ -237,6 +238,7 @@ async fn build_attempt_context(
|
||||||
current_block_number,
|
current_block_number,
|
||||||
previous_hash,
|
previous_hash,
|
||||||
previous_difficulty,
|
previous_difficulty,
|
||||||
|
reward_value,
|
||||||
verification_service,
|
verification_service,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -279,8 +281,7 @@ pub async fn mine_block_internal(
|
||||||
let block_hash = vrf_block.hash().await;
|
let block_hash = vrf_block.hash().await;
|
||||||
|
|
||||||
// Every mined block begins with a consensus-created reward transaction.
|
// Every mined block begins with a consensus-created reward transaction.
|
||||||
let rewards_transaction =
|
let rewards_transaction = create_rewards_transaction(timestamp, ctx.reward_value).await;
|
||||||
create_rewards_transaction(&ctx.miner_short, timestamp, &ctx.db).await;
|
|
||||||
let new_block = Block {
|
let new_block = Block {
|
||||||
vrf_block,
|
vrf_block,
|
||||||
transactions: vec![Transaction::Rewards(rewards_transaction)],
|
transactions: vec![Transaction::Rewards(rewards_transaction)],
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,6 @@ pub struct MiningAttemptContext {
|
||||||
pub current_block_number: u32,
|
pub current_block_number: u32,
|
||||||
pub previous_hash: String,
|
pub previous_hash: String,
|
||||||
pub previous_difficulty: u64,
|
pub previous_difficulty: u64,
|
||||||
|
pub reward_value: u64,
|
||||||
pub verification_service: Arc<VerificationService>,
|
pub verification_service: Arc<VerificationService>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -167,11 +167,9 @@ pub async fn undo_transactions(
|
||||||
// outcome must be reconsidered before replacement blocks are replayed.
|
// outcome must be reconsidered before replacement blocks are replayed.
|
||||||
reset_all_torrent_statuses().await;
|
reset_all_torrent_statuses().await;
|
||||||
|
|
||||||
// rebuild mined counts after rollback, then fetch and save the
|
// Counts are corrected incrementally: rollback decrements each removed
|
||||||
// replacement blocks, and finally rebuild mined counts again
|
// block above, and replay/save increments each accepted replacement.
|
||||||
NodeInfo::rebuild_mined_counts_from_chain(¶ms.db).await?;
|
|
||||||
save_new_blocks(¶ms, replay_to_height, wallet, true_start_height).await?;
|
save_new_blocks(¶ms, replay_to_height, wallet, true_start_height).await?;
|
||||||
rebuild_chain_state_cache(¶ms.db).await?;
|
rebuild_chain_state_cache(¶ms.db).await?;
|
||||||
NodeInfo::rebuild_mined_counts_from_chain(¶ms.db).await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,29 +45,6 @@ impl NodeInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn chain_mined_count_at_least(
|
|
||||||
address: &str,
|
|
||||||
through_height: u32,
|
|
||||||
threshold: u8,
|
|
||||||
) -> Result<bool, String> {
|
|
||||||
if threshold == 0 {
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut mined_count = 0_u8;
|
|
||||||
for block_number in 1..=through_height {
|
|
||||||
let header = load_block_header(block_number).await?;
|
|
||||||
if header.unmined_block.miner == address {
|
|
||||||
mined_count = mined_count.saturating_add(1);
|
|
||||||
if mined_count >= threshold {
|
|
||||||
return Ok(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn set_deleted_block_from_mapping(address: &str, deleted_block: u32) {
|
pub async fn set_deleted_block_from_mapping(address: &str, deleted_block: u32) {
|
||||||
let mut map = ADDRESS_MAP.lock().await;
|
let mut map = ADDRESS_MAP.lock().await;
|
||||||
if let Some(node_info) = map.get_mut(address) {
|
if let Some(node_info) = map.get_mut(address) {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::common::skein::skein_256_hash_data;
|
||||||
use crate::config::SETTINGS;
|
use crate::config::SETTINGS;
|
||||||
use crate::encode;
|
use crate::encode;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::log::{error, info, warn};
|
use crate::log::{info, warn};
|
||||||
use crate::miner::flag::{
|
use crate::miner::flag::{
|
||||||
clear_mining_stop_request, request_mining_stop, set_mining_state, set_node_mode, MiningState,
|
clear_mining_stop_request, request_mining_stop, set_mining_state, set_node_mode, MiningState,
|
||||||
NodeMode,
|
NodeMode,
|
||||||
|
|
@ -19,7 +19,6 @@ use crate::records::memory::connections::{
|
||||||
set_reconnect_context, startup_synced_peer_streams, CONNECTIONS,
|
set_reconnect_context, startup_synced_peer_streams, CONNECTIONS,
|
||||||
};
|
};
|
||||||
use crate::records::memory::enums::{ClientType, ConnectionType};
|
use crate::records::memory::enums::{ClientType, ConnectionType};
|
||||||
use crate::records::memory::network_mapping::NodeInfo;
|
|
||||||
use crate::records::memory::response_channels::{reserve_entry, Command};
|
use crate::records::memory::response_channels::{reserve_entry, Command};
|
||||||
use crate::records::memory::structs::{Connection, StoreConnectionParams};
|
use crate::records::memory::structs::{Connection, StoreConnectionParams};
|
||||||
use crate::rpc::client::handshake::connect_and_handshake;
|
use crate::rpc::client::handshake::connect_and_handshake;
|
||||||
|
|
@ -201,10 +200,6 @@ pub async fn bootstrap_peer_discovery(mut params: BootstrapParams) -> Result<(),
|
||||||
let post_sync_remote_height =
|
let post_sync_remote_height =
|
||||||
request_remote_height(stream.clone(), params.map.clone(), current_key.clone()).await?;
|
request_remote_height(stream.clone(), params.map.clone(), current_key.clone()).await?;
|
||||||
|
|
||||||
if let Err(err) = NodeInfo::rebuild_mined_counts_from_chain(¶ms.db).await {
|
|
||||||
error!("[startup] failed to rebuild mined counts before startup orphan check: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let imported_candidates =
|
let imported_candidates =
|
||||||
match hydrate_torrent_candidates(stream.clone(), params.map.clone(), current_key.clone())
|
match hydrate_torrent_candidates(stream.clone(), params.map.clone(), current_key.clone())
|
||||||
.await
|
.await
|
||||||
|
|
@ -241,9 +236,6 @@ pub async fn bootstrap_peer_discovery(mut params: BootstrapParams) -> Result<(),
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("[sync] post-sync checks complete, mining grace period started");
|
info!("[sync] post-sync checks complete, mining grace period started");
|
||||||
if let Err(err) = NodeInfo::rebuild_mined_counts_from_chain(¶ms.db).await {
|
|
||||||
error!("[startup] failed to rebuild mined counts after startup sync: {err}");
|
|
||||||
}
|
|
||||||
for (peer_key, _) in startup_synced_peer_streams().await {
|
for (peer_key, _) in startup_synced_peer_streams().await {
|
||||||
mark_peer_operational(&peer_key, params.map.clone()).await;
|
mark_peer_operational(&peer_key, params.map.clone()).await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ use crate::records::block_height::get_block_height::get_height;
|
||||||
use crate::records::memory::connections::{
|
use crate::records::memory::connections::{
|
||||||
mark_peer_network_map_synced, mark_peer_operational, mark_peer_wallet_registry_synced,
|
mark_peer_network_map_synced, mark_peer_operational, mark_peer_wallet_registry_synced,
|
||||||
};
|
};
|
||||||
use crate::records::memory::network_mapping::NodeInfo;
|
|
||||||
use crate::records::memory::response_channels::generate_uid;
|
use crate::records::memory::response_channels::generate_uid;
|
||||||
use crate::records::memory::response_channels::Command;
|
use crate::records::memory::response_channels::Command;
|
||||||
use crate::records::memory::structs::Connection;
|
use crate::records::memory::structs::Connection;
|
||||||
|
|
@ -99,10 +98,6 @@ async fn sync_incoming_peer_before_operational(
|
||||||
let post_sync_remote_height =
|
let post_sync_remote_height =
|
||||||
request_remote_height(stream.clone(), map.clone(), connections_key.to_string()).await?;
|
request_remote_height(stream.clone(), map.clone(), connections_key.to_string()).await?;
|
||||||
|
|
||||||
if let Err(err) = NodeInfo::rebuild_mined_counts_from_chain(db).await {
|
|
||||||
error!("[startup] failed to rebuild mined counts before incoming orphan check: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
let imported_candidates = match hydrate_torrent_candidates(
|
let imported_candidates = match hydrate_torrent_candidates(
|
||||||
stream.clone(),
|
stream.clone(),
|
||||||
map.clone(),
|
map.clone(),
|
||||||
|
|
@ -263,10 +258,6 @@ async fn complete_incoming_miner_setup(
|
||||||
connections_key.to_string(),
|
connections_key.to_string(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = NodeInfo::rebuild_mined_counts_from_chain(db).await {
|
|
||||||
error!("[startup] failed to rebuild mined counts after incoming handshake: {err}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function validates incoming handshake and determined
|
// this function validates incoming handshake and determined
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,9 @@ impl RewardsTransaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
// New miners receive zero reward until their mined-count history
|
// New miners receive zero reward until their mined-count history
|
||||||
// reaches the maturity threshold.
|
// reaches the maturity threshold. The network map is the single
|
||||||
|
// runtime source for this count; startup, sync, save, and reorg
|
||||||
|
// paths are responsible for keeping it corrected from chain state.
|
||||||
let reward_value = if NodeInfo::get_mined_count(&miner).await < REWARD_MATURITY_BLOCKS {
|
let reward_value = if NodeInfo::get_mined_count(&miner).await < REWARD_MATURITY_BLOCKS {
|
||||||
0_u64
|
0_u64
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue