From 9cc17ac0b5a03f96e88c5ee54df4014317eb7910 Mon Sep 17 00:00:00 2001 From: viraladmin <00purple@gmail.com> Date: Sun, 14 Jun 2026 09:52:52 -0600 Subject: [PATCH] network mapping fix --- src/miner/block_rewards.rs | 34 +++++++------------ src/miner/mining.rs | 7 ++-- src/miner/structs.rs | 1 + src/orphans/undo_block_transactions.rs | 6 ++-- .../memory/network_mapping/mined_counts.rs | 23 ------------- src/rpc/client/handshake_processing.rs | 10 +----- src/rpc/server/handshake.rs | 9 ----- .../async_funcs/verify_rewards.rs | 4 ++- 8 files changed, 23 insertions(+), 71 deletions(-) diff --git a/src/miner/block_rewards.rs b/src/miner/block_rewards.rs index 99b7d31..1867681 100644 --- a/src/miner/block_rewards.rs +++ b/src/miner/block_rewards.rs @@ -1,9 +1,6 @@ use crate::blocks::rewards::{RewardsTransaction, UnsignedRewardsTransaction}; 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::sled::Db; const REWARD_MATURITY_BLOCKS: u8 = 100; @@ -26,29 +23,22 @@ pub async fn calculate_block_reward(block_height: u32) -> u64 { reward } -pub async fn create_rewards_transaction( - short_address: &str, - timestamp: u32, - db: &Db, -) -> RewardsTransaction { +pub async fn reward_value_for_miner_at_height(short_address: &str, block_height: u32) -> u64 { + // New miners must first prove participation before receiving the + // block subsidy. The mined count is maintained in the network map and + // rebuilt from headers only during startup/recovery/reorg correction. + 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 // mined block using the current reward schedule. 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 // consensus rules rather than by a wallet spending funds. let unsigned_rewards = UnsignedRewardsTransaction::new(txtype, timestamp, value).await; diff --git a/src/miner/mining.rs b/src/miner/mining.rs index 41bb396..dd8e258 100644 --- a/src/miner/mining.rs +++ b/src/miner/mining.rs @@ -1,7 +1,7 @@ use crate::blocks::block::{Block, UnminedBlock}; use crate::common::types::Transaction; 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::flag::{is_mining_stop_requested, is_normal_mode, set_mining_state, MiningState}; 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_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 { db: db.clone(), @@ -237,6 +238,7 @@ async fn build_attempt_context( current_block_number, previous_hash, previous_difficulty, + reward_value, verification_service, }) } @@ -279,8 +281,7 @@ pub async fn mine_block_internal( let block_hash = vrf_block.hash().await; // Every mined block begins with a consensus-created reward transaction. - let rewards_transaction = - create_rewards_transaction(&ctx.miner_short, timestamp, &ctx.db).await; + let rewards_transaction = create_rewards_transaction(timestamp, ctx.reward_value).await; let new_block = Block { vrf_block, transactions: vec![Transaction::Rewards(rewards_transaction)], diff --git a/src/miner/structs.rs b/src/miner/structs.rs index 18f4da8..e8d0051 100644 --- a/src/miner/structs.rs +++ b/src/miner/structs.rs @@ -13,5 +13,6 @@ pub struct MiningAttemptContext { pub current_block_number: u32, pub previous_hash: String, pub previous_difficulty: u64, + pub reward_value: u64, pub verification_service: Arc, } diff --git a/src/orphans/undo_block_transactions.rs b/src/orphans/undo_block_transactions.rs index 81e22ec..acb2c0c 100644 --- a/src/orphans/undo_block_transactions.rs +++ b/src/orphans/undo_block_transactions.rs @@ -167,11 +167,9 @@ pub async fn undo_transactions( // outcome must be reconsidered before replacement blocks are replayed. reset_all_torrent_statuses().await; - // rebuild mined counts after rollback, then fetch and save the - // replacement blocks, and finally rebuild mined counts again - NodeInfo::rebuild_mined_counts_from_chain(¶ms.db).await?; + // Counts are corrected incrementally: rollback decrements each removed + // block above, and replay/save increments each accepted replacement. save_new_blocks(¶ms, replay_to_height, wallet, true_start_height).await?; rebuild_chain_state_cache(¶ms.db).await?; - NodeInfo::rebuild_mined_counts_from_chain(¶ms.db).await?; Ok(()) } diff --git a/src/records/memory/network_mapping/mined_counts.rs b/src/records/memory/network_mapping/mined_counts.rs index 4cfce4d..b7cf93b 100644 --- a/src/records/memory/network_mapping/mined_counts.rs +++ b/src/records/memory/network_mapping/mined_counts.rs @@ -45,29 +45,6 @@ impl NodeInfo { } } - pub async fn chain_mined_count_at_least( - address: &str, - through_height: u32, - threshold: u8, - ) -> Result { - 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) { let mut map = ADDRESS_MAP.lock().await; if let Some(node_info) = map.get_mut(address) { diff --git a/src/rpc/client/handshake_processing.rs b/src/rpc/client/handshake_processing.rs index ddaab2d..1230ae5 100644 --- a/src/rpc/client/handshake_processing.rs +++ b/src/rpc/client/handshake_processing.rs @@ -5,7 +5,7 @@ use crate::common::skein::skein_256_hash_data; use crate::config::SETTINGS; use crate::encode; use crate::io; -use crate::log::{error, info, warn}; +use crate::log::{info, warn}; use crate::miner::flag::{ clear_mining_stop_request, request_mining_stop, set_mining_state, set_node_mode, MiningState, NodeMode, @@ -19,7 +19,6 @@ use crate::records::memory::connections::{ set_reconnect_context, startup_synced_peer_streams, CONNECTIONS, }; 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::structs::{Connection, StoreConnectionParams}; 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 = 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 = match hydrate_torrent_candidates(stream.clone(), params.map.clone(), current_key.clone()) .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"); - 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 { mark_peer_operational(&peer_key, params.map.clone()).await; } diff --git a/src/rpc/server/handshake.rs b/src/rpc/server/handshake.rs index 845cc96..403c3c6 100644 --- a/src/rpc/server/handshake.rs +++ b/src/rpc/server/handshake.rs @@ -11,7 +11,6 @@ use crate::records::block_height::get_block_height::get_height; use crate::records::memory::connections::{ 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::Command; use crate::records::memory::structs::Connection; @@ -99,10 +98,6 @@ async fn sync_incoming_peer_before_operational( let post_sync_remote_height = 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( stream.clone(), map.clone(), @@ -263,10 +258,6 @@ async fn complete_incoming_miner_setup( 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 diff --git a/src/verifications/async_funcs/verify_rewards.rs b/src/verifications/async_funcs/verify_rewards.rs index 9ad7c2c..7af796c 100644 --- a/src/verifications/async_funcs/verify_rewards.rs +++ b/src/verifications/async_funcs/verify_rewards.rs @@ -24,7 +24,9 @@ impl RewardsTransaction { } // 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 { 0_u64 } else {