commit 765cce8ff8996d96fc8cd3b7584c23b4c4ccae15
parent faed2d5f0579bf1016c0f9c9c949ca87f321efc7
Author: Joris Hartog <jorishartog@hotmail.com>
Date: Sun, 2 Aug 2026 02:15:34 +0200
Remove required burn mine reward setting
Diffstat:
9 files changed, 133 insertions(+), 801 deletions(-)
diff --git a/src/adapters/chain_store.rs b/src/adapters/chain_store.rs
@@ -9,7 +9,7 @@ use rusqlite::{Connection, OptionalExtension, params};
use serde::Serialize;
-use crate::domain::{Amount, ChainSnapshot, Ledger, Transaction};
+use crate::domain::{Amount, ChainSnapshot, Ledger, MINE_REWARD, Transaction};
const SCHEMA: &str = r#"
CREATE TABLE IF NOT EXISTS chain_snapshots (
@@ -331,13 +331,10 @@ fn metrics_from_snapshot(snapshot: &ChainSnapshot) -> Result<Vec<BlockMetricRow>
.checked_add(*amount)
.context("block metric burns overflow")?;
}
- Transaction::Mine {
- required_burn_amount,
- ..
- } => {
+ Transaction::Mine { .. } => {
mine_count += 1;
mine_issued_amount = mine_issued_amount
- .checked_add(*required_burn_amount)
+ .checked_add(MINE_REWARD)
.and_then(|amount| amount.checked_add(transaction.fee()))
.context("block metric mine issuance overflow")?;
}
diff --git a/src/adapters/config_store.rs b/src/adapters/config_store.rs
@@ -9,7 +9,7 @@ use std::{
use anyhow::{Context, Result, bail};
use serde::{Deserialize, Serialize};
-use crate::domain::{Amount, DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS, MICRO_IUNA};
+use crate::domain::{Amount, MICRO_IUNA};
const CONFIG_FILE_VERSION: u32 = 1;
const AMOUNT_UNIT_MICROIUNA: &str = "microiuna";
@@ -26,7 +26,6 @@ pub struct UiConfig {
pub pow_mining_enabled: bool,
pub burn_per_block: Amount,
pub burn_fee: Amount,
- pub mine_required_burn_multiplier_bps: u16,
pub keep_track_of_metrics: bool,
pub p2p_accept_inbound: bool,
pub p2p_announce_addr: Option<String>,
@@ -42,7 +41,6 @@ impl Default for UiConfig {
pow_mining_enabled: false,
burn_per_block: DEFAULT_BURN_AMOUNT,
burn_fee: DEFAULT_BURN_FEE,
- mine_required_burn_multiplier_bps: DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS,
keep_track_of_metrics: false,
p2p_accept_inbound: false,
p2p_announce_addr: None,
@@ -68,8 +66,6 @@ struct ConfigFile {
#[serde(default)]
burn_fee: Option<Amount>,
#[serde(default)]
- mine_required_burn_multiplier_bps: Option<u16>,
- #[serde(default)]
keep_track_of_metrics: bool,
#[serde(default)]
p2p_accept_inbound: Option<bool>,
@@ -104,7 +100,6 @@ pub fn save(path: &Path, config: &UiConfig) -> Result<()> {
pow_mining_enabled: config.pow_mining_enabled,
burn_per_block: config.burn_per_block,
burn_fee: Some(config.burn_fee),
- mine_required_burn_multiplier_bps: Some(config.mine_required_burn_multiplier_bps),
keep_track_of_metrics: config.keep_track_of_metrics,
p2p_accept_inbound: Some(config.p2p_accept_inbound),
p2p_announce_addr: config.p2p_announce_addr.clone(),
@@ -156,9 +151,6 @@ fn load(path: &Path) -> Result<UiConfig> {
.burn_fee
.map(|fee| fee.saturating_mul(scale))
.unwrap_or(DEFAULT_BURN_FEE),
- mine_required_burn_multiplier_bps: stored
- .mine_required_burn_multiplier_bps
- .unwrap_or(DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS),
keep_track_of_metrics: stored.keep_track_of_metrics,
p2p_accept_inbound,
p2p_announce_addr: stored.p2p_announce_addr,
@@ -204,7 +196,7 @@ mod tests {
assert!(stored.contains("\"burn_per_block\": 100"));
assert!(stored.contains("\"burn_fee\": 100"));
assert!(!stored.contains("\"pow_mine_fee\""));
- assert!(stored.contains("\"mine_required_burn_multiplier_bps\": 8000"));
+ assert!(!stored.contains("required_burn"));
assert!(stored.contains("\"keep_track_of_metrics\": false"));
assert!(stored.contains("\"p2p_accept_inbound\": false"));
assert!(stored.contains("\"p2p_announce_addr\": null"));
@@ -225,7 +217,6 @@ mod tests {
pow_mining_enabled: true,
burn_per_block: 50 * MICRO_IUNA,
burn_fee: 3 * MICRO_IUNA,
- mine_required_burn_multiplier_bps: 9_000,
keep_track_of_metrics: true,
p2p_accept_inbound: true,
p2p_announce_addr: Some("203.0.113.10:9444".to_string()),
@@ -241,7 +232,6 @@ mod tests {
assert!(config.pow_mining_enabled);
assert_eq!(config.burn_per_block, 50 * MICRO_IUNA);
assert_eq!(config.burn_fee, 3 * MICRO_IUNA);
- assert_eq!(config.mine_required_burn_multiplier_bps, 9_000);
assert!(config.keep_track_of_metrics);
assert!(config.p2p_accept_inbound);
assert_eq!(
@@ -285,7 +275,6 @@ mod tests {
assert!(!config.pow_mining_enabled);
assert_eq!(config.burn_per_block, 0);
assert_eq!(config.burn_fee, DEFAULT_BURN_FEE);
- assert_eq!(config.mine_required_burn_multiplier_bps, 8_000);
assert!(!config.keep_track_of_metrics);
assert!(!config.p2p_accept_inbound);
assert_eq!(config.peers, vec!["127.0.0.1:9444"]);
@@ -347,7 +336,6 @@ mod tests {
assert!(config.mining_enabled);
assert_eq!(config.burn_per_block, 2 * MICRO_IUNA);
assert_eq!(config.burn_fee, MICRO_IUNA);
- assert_eq!(config.mine_required_burn_multiplier_bps, 8_000);
}
#[test]
@@ -366,7 +354,6 @@ mod tests {
"burn_per_block": 2000000,
"burn_fee": 3,
"pow_mine_fee": 5,
- "mine_required_burn_multiplier_bps": 7500,
"peers": []
}}
"#
@@ -379,6 +366,5 @@ mod tests {
assert!(config.mining_enabled);
assert_eq!(config.burn_per_block, 2 * MICRO_IUNA);
assert_eq!(config.burn_fee, 3);
- assert_eq!(config.mine_required_burn_multiplier_bps, 7_500);
}
}
diff --git a/src/adapters/http.rs b/src/adapters/http.rs
@@ -33,8 +33,8 @@ use crate::{
FeeEstimate, NodeStatus, PeerDirection, PeerInfo, SharedNode, SharedPeerBook, StratumStatus,
},
domain::{
- Amount, Block, DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS, Ledger, MINE_FINALIZER_FEE,
- OutPoint, Transaction, TxInput, TxOutput, hex_hash,
+ Amount, Block, Ledger, MINE_FINALIZER_FEE, MINE_REWARD, OutPoint, Transaction, TxInput,
+ TxOutput, hex_hash,
},
};
@@ -138,7 +138,6 @@ struct BurnSettingsForm {
#[derive(Debug, Deserialize)]
struct PowMiningForm {
enabled: bool,
- multiplier_bps: Option<u16>,
}
#[derive(Debug, Deserialize)]
@@ -945,9 +944,9 @@ async fn api_burn_fee_estimate_form(
async fn api_mine_fee_estimate_form(
State(state): State<HttpState>,
- Form(form): Form<PowMiningForm>,
+ Form(_form): Form<BTreeMap<String, String>>,
) -> Json<FeeEstimateResponse> {
- fee_estimate_json(estimate_mine_fee(&state, form).await)
+ fee_estimate_json(estimate_mine_fee(&state).await)
}
async fn api_burn_per_block_form(
@@ -966,15 +965,7 @@ async fn api_pow_mining_form(
State(state): State<HttpState>,
Form(form): Form<PowMiningForm>,
) -> Json<ActionResponse> {
- action_json(
- set_pow_mining(
- &state,
- form.enabled,
- form.multiplier_bps
- .unwrap_or(DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS),
- )
- .await,
- )
+ action_json(set_pow_mining(&state, form.enabled).await)
}
async fn api_metrics_settings_form(
@@ -1097,29 +1088,21 @@ async fn persist_burn_settings_config(
config_store::save(config_path, &config)
}
-async fn set_pow_mining(state: &HttpState, enabled: bool, multiplier_bps: u16) -> Result<()> {
+async fn set_pow_mining(state: &HttpState, enabled: bool) -> Result<()> {
{
let mut node = state.node.lock().await;
- node.set_pow_mining_settings(enabled, multiplier_bps)?;
+ node.set_pow_mining_enabled(enabled);
}
- persist_pow_mining_config(
- &state.ui_config,
- &state.config_path,
- enabled,
- multiplier_bps,
- )
- .await
+ persist_pow_mining_config(&state.ui_config, &state.config_path, enabled).await
}
async fn persist_pow_mining_config(
ui_config: &Arc<Mutex<UiConfig>>,
config_path: &Path,
enabled: bool,
- multiplier_bps: u16,
) -> Result<()> {
let mut config = ui_config.lock().await;
config.pow_mining_enabled = enabled;
- config.mine_required_burn_multiplier_bps = multiplier_bps;
config_store::save(config_path, &config)
}
@@ -1638,7 +1621,6 @@ fn wallet_transaction_row(
}),
Transaction::Mine {
recipient,
- required_burn_amount,
difficulty_bits,
signature,
..
@@ -1646,12 +1628,12 @@ fn wallet_transaction_row(
kind: "mine",
from: "pow".to_string(),
to: Some(recipient.clone()),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
fee: tx.fee(),
inputs: Vec::new(),
outputs: vec![TxOutput {
address: recipient.clone(),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
}],
change: Vec::new(),
signature: signature.clone(),
@@ -1748,7 +1730,6 @@ fn ui_transaction(
},
Transaction::Mine {
recipient,
- required_burn_amount,
difficulty_bits,
signature,
..
@@ -1756,12 +1737,12 @@ fn ui_transaction(
kind: "mine",
from: "pow".to_string(),
to: Some(recipient.clone()),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
fee: transaction.fee(),
inputs: Vec::new(),
outputs: vec![TxOutput {
address: recipient.clone(),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
}],
change: Vec::new(),
signature: signature.clone(),
@@ -1877,13 +1858,9 @@ fn index_transaction_outputs(
let created_outputs = match transaction {
Transaction::Transfer { outputs, .. } => outputs.clone(),
Transaction::Burn { change, .. } => change.clone(),
- Transaction::Mine {
- recipient,
- required_burn_amount,
- ..
- } => vec![TxOutput {
+ Transaction::Mine { recipient, .. } => vec![TxOutput {
address: recipient.clone(),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
}],
Transaction::BurnClaim { .. } => Vec::new(),
};
@@ -2047,7 +2024,7 @@ async fn estimate_burn_fee(state: &HttpState, form: BurnSettingsForm) -> Result<
.estimate_burn_fee(form.amount, fee_per_byte)
}
-async fn estimate_mine_fee(state: &HttpState, _form: PowMiningForm) -> Result<FeeEstimate> {
+async fn estimate_mine_fee(state: &HttpState) -> Result<FeeEstimate> {
state
.node
.lock()
@@ -2858,7 +2835,7 @@ const INDEX_HTML: &str = r#"<!doctype html>
.block-card { flex-basis: 108px; }
}
</style>
- <script defer src="/assets/iuna-ui.js?v=70"></script>
+ <script defer src="/assets/iuna-ui.js?v=71"></script>
<script defer src="/assets/alpine.min.js"></script>
</head>
<body x-data="iunaApp()" x-init="init()" @keydown.window.escape="closeModals()" x-cloak>
@@ -3070,17 +3047,13 @@ const INDEX_HTML: &str = r#"<!doctype html>
</div>
<div class="panel">
<h3>Mine</h3>
- <div class="panel-description">Search for PoW actions that mint IUNA when blocks have enough burns.</div>
- <form class="mine-settings-form" @submit.prevent="savePowMining">
+ <div class="panel-description">Search for PoW actions that mint a fixed IUNA reward.</div>
+ <div class="mine-settings-form">
<div class="mine-action-row">
<div class="mine-stats" aria-label="PoW issuance settings">
<div class="mine-stat">
<div class="mine-stat-label">You receive</div>
- <div class="mine-stat-value money">IUNA <span x-text="amountLabel(powMineNetReward())"></span></div>
- </div>
- <div class="mine-stat">
- <div class="mine-stat-label">Needs burns</div>
- <div class="mine-stat-value">IUNA <span x-text="amountLabel(powMineRequiredBurn())"></span></div>
+ <div class="mine-stat-value money">IUNA <span x-text="amountLabel(powMineReward())"></span></div>
</div>
<div class="mine-stat">
<div class="mine-stat-label">Finalizer earns</div>
@@ -3097,20 +3070,8 @@ const INDEX_HTML: &str = r#"<!doctype html>
<span class="toggle-text" x-text="powMiningEnabled ? 'On' : 'Off'"></span>
</label>
</div>
- <div class="mine-reward-control">
- <div class="mine-reward-head"><span>Reward setting</span><strong>IUNA <span x-text="amountLabel(powMineNetReward())"></span></strong></div>
- <input x-model="powRequiredBurnMultiplierDraft" @input="powRequiredBurnMultiplierDirty = true" type="range" min="0.1" max="1" step="0.05" aria-label="PoW reward setting">
- <div class="mine-slider-hints"><span>Easier to include</span><span>Higher reward</span></div>
- <div class="mine-include-status" :class="powMineIncludeStatus().kind">
- <span x-text="powMineIncludeStatus().label"></span>
- <span x-text="powMineIncludeStatus().recent"></span>
- </div>
- </div>
- <div class="mine-save-row" x-show="powRequiredBurnMultiplierDirty">
- <button class="primary" type="submit">Save</button>
- </div>
<div class="fee-preview" x-text="autoPowStatusLabel()"></div>
- </form>
+ </div>
<div class="panel-separator"></div>
<div class="stratum-config">
<div class="stratum-note">Start the node with <code>--stratum 0.0.0.0:3333</code> to expose a Stratum V1 endpoint for ASIC miners. Use the pool URL below in the miner configuration.</div>
@@ -4723,7 +4684,7 @@ mod tests {
#[test]
fn metrics_screen_includes_block_range_filter() {
- assert!(super::INDEX_HTML.contains("iuna-ui.js?v=70"));
+ assert!(super::INDEX_HTML.contains("iuna-ui.js?v=71"));
assert!(super::INDEX_HTML.contains("aria-label=\"Metrics block range\""));
assert!(super::INDEX_HTML.contains("setMetricsRange(100)"));
assert!(super::INDEX_HTML.contains("setMetricsRange(1000)"));
@@ -4731,12 +4692,14 @@ mod tests {
}
#[test]
- fn mine_screen_shows_recent_burn_fit_status() {
+ fn mine_screen_shows_fixed_pow_reward_without_burn_slider() {
let app_js = include_str!("../../www/assets/iuna-ui.js");
- assert!(app_js.contains("Recent high:"));
- assert!(app_js.contains("May wait for bigger burn blocks"));
- assert!(super::INDEX_HTML.contains("Easier to include"));
- assert!(super::INDEX_HTML.contains("Higher reward"));
+ assert!(app_js.contains("powMineReward()"));
+ assert!(
+ super::INDEX_HTML.contains("Search for PoW actions that mint a fixed IUNA reward.")
+ );
+ assert!(super::INDEX_HTML.contains("amountLabel(powMineReward())"));
+ assert!(!super::INDEX_HTML.contains("Needs burns"));
}
async fn auth_test_state(config_path: std::path::PathBuf, config: UiConfig) -> HttpState {
@@ -4938,13 +4901,12 @@ mod tests {
let initial_config = ui_config.lock().await.clone();
config_store::save(&config_path, &initial_config).expect("initial config should save");
- persist_pow_mining_config(&ui_config, &config_path, true, 7_500)
+ persist_pow_mining_config(&ui_config, &config_path, true)
.await
.unwrap();
let config = config_store::load_or_create(&config_path).unwrap();
assert!(config.pow_mining_enabled);
- assert_eq!(config.mine_required_burn_multiplier_bps, 7_500);
}
#[test]
diff --git a/src/app.rs b/src/app.rs
@@ -14,10 +14,9 @@ use tokio::sync::Mutex;
use crate::domain::{
Amount, BURN_CLAIM_SEEN_WINDOW_BLOCKS, Block, BurnSeen, ChainSnapshot, ChainStatus,
- DEFAULT_FEE_PER_BYTE, DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS, DEFAULT_TRANSACTION_FEE,
- Ledger, MAX_PENDING_TRANSACTIONS, MINE_FINALIZER_FEE, OutPoint, PreparedBlock,
- StratumMineShare, StratumMineTemplate, Transaction, TransactionSubmitOutcome,
- VDF_TARGET_BLOCK_MS, Wallet, hex_hash, run_vdf,
+ DEFAULT_FEE_PER_BYTE, DEFAULT_TRANSACTION_FEE, Ledger, MAX_PENDING_TRANSACTIONS,
+ MINE_FINALIZER_FEE, OutPoint, PreparedBlock, StratumMineShare, StratumMineTemplate,
+ Transaction, TransactionSubmitOutcome, VDF_TARGET_BLOCK_MS, Wallet, hex_hash, run_vdf,
};
pub type SharedNode = Arc<Mutex<NodeCore>>;
@@ -35,8 +34,6 @@ pub const PEER_MISBEHAVIOR_BAN_SCORE: u32 = 3;
pub const PEER_MISBEHAVIOR_BAN_MS: u64 = 10 * 60 * 1_000;
pub const PEER_CLOCK_OFFSET_ACCEPTANCE_MS: i64 = 10 * 60 * 1_000;
const PEER_CLOCK_OFFSET_STALE_MS: u64 = 20 * 60 * 1_000;
-const MIN_MINE_REQUIRED_BURN_MULTIPLIER_BPS: u16 = 1_000;
-const MAX_MINE_REQUIRED_BURN_MULTIPLIER_BPS: u16 = 10_000;
const AUTO_POW_NONCE_ATTEMPTS_PER_TICK: u64 = 8;
static DEBUG_LOGGING: AtomicBool = AtomicBool::new(false);
@@ -213,8 +210,6 @@ pub struct MiningStatus {
pub burn_per_block: Amount,
pub automatic_burn_fee: Amount,
pub automatic_pow_mine_fee: Amount,
- pub automatic_pow_required_burn_amount: Amount,
- pub mine_required_burn_multiplier_bps: u16,
pub last_auto_pow_mine_anchor: Option<String>,
pub last_auto_pow_mine_status: Option<String>,
pub vdf_rounds: u64,
@@ -260,7 +255,6 @@ pub struct NodeCore {
ledger: Ledger,
automatic_mining_enabled: bool,
pow_mining_enabled: bool,
- mine_required_burn_multiplier_bps: u16,
burn_per_block: Amount,
burn_fee: Amount,
last_auto_burn_height: Option<u64>,
@@ -347,7 +341,6 @@ impl NodeCore {
ledger,
automatic_mining_enabled,
pow_mining_enabled: false,
- mine_required_burn_multiplier_bps: DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS,
burn_per_block,
burn_fee,
last_auto_burn_height: None,
@@ -566,8 +559,6 @@ impl NodeCore {
burn_per_block: self.burn_per_block,
automatic_burn_fee: self.burn_fee,
automatic_pow_mine_fee: MINE_FINALIZER_FEE,
- automatic_pow_required_burn_amount: self.pow_required_burn_amount(),
- mine_required_burn_multiplier_bps: self.mine_required_burn_multiplier_bps,
last_auto_pow_mine_anchor: self.last_auto_pow_mine_anchor.clone(),
last_auto_pow_mine_status: if self.pow_mining_enabled && !self.has_real_chain() {
Some("waiting for a real chain before PoW mining can start".to_string())
@@ -628,21 +619,6 @@ impl NodeCore {
}
}
- pub fn set_pow_mining_settings(&mut self, enabled: bool, multiplier_bps: u16) -> Result<()> {
- validate_mine_required_burn_multiplier(multiplier_bps)?;
- self.pow_mining_enabled = enabled;
- self.mine_required_burn_multiplier_bps = multiplier_bps;
- self.auto_pow_mine_cursor = None;
- if !enabled {
- self.last_auto_pow_mine_anchor = None;
- self.last_auto_pow_mine_status = None;
- } else {
- self.last_auto_pow_mine_status =
- Some("waiting for next automatic PoW mining tick".to_string());
- }
- Ok(())
- }
-
pub fn burn(&mut self, amount: Amount) -> Result<Transaction> {
self.burn_with_fee(amount, 0)
}
@@ -740,7 +716,7 @@ impl NodeCore {
}
pub fn mine_pow_reward(&mut self) -> Result<Transaction> {
- let (tx, _) = self.build_mine_with_required_burn_estimate()?;
+ let (tx, _) = self.build_mine_estimate()?;
if self.ledger.submit_transaction(tx.clone())? {
self.outbox.push(GossipEnvelope::Transaction(tx.clone()));
}
@@ -748,8 +724,7 @@ impl NodeCore {
}
pub fn estimate_mine_fee(&self, _fee_per_byte: Amount) -> Result<FeeEstimate> {
- self.build_mine_with_required_burn_estimate()
- .map(|(_, estimate)| estimate)
+ self.build_mine_estimate().map(|(_, estimate)| estimate)
}
pub fn external_mine_job(
@@ -763,12 +738,9 @@ impl NodeCore {
.last()
.context("cannot build mine job without a chain tip")?;
let difficulty_bits = self.ledger.current_mine_difficulty_bits();
- let required_burn_amount =
- self.external_mine_required_burn_amount(&recipient, &tip.hash, difficulty_bits)?;
Ok(ExternalMineJob {
template: self.ledger.stratum_mine_template(
recipient,
- required_burn_amount,
&tip.hash,
salt,
difficulty_bits,
@@ -940,11 +912,8 @@ impl NodeCore {
})
}
- fn build_mine_with_required_burn_estimate(&self) -> Result<(Transaction, FeeEstimate)> {
- let tx = self.ledger.build_mine_with_required_burn(
- self.wallet.address(),
- self.pow_required_burn_amount(),
- )?;
+ fn build_mine_estimate(&self) -> Result<(Transaction, FeeEstimate)> {
+ let tx = self.ledger.build_mine(self.wallet.address())?;
Ok((
tx.clone(),
FeeEstimate {
@@ -954,33 +923,6 @@ impl NodeCore {
))
}
- fn external_mine_required_burn_amount(
- &self,
- _recipient: &str,
- _anchor: &str,
- _difficulty_bits: u32,
- ) -> Result<Amount> {
- Ok(self.pow_required_burn_amount())
- }
-
- fn local_mine_required_burn_amount(
- &self,
- _recipient: &str,
- _anchor: &str,
- _salt: u64,
- _difficulty_bits: u32,
- _fee_per_byte: Amount,
- ) -> Result<Amount> {
- Ok(self.pow_required_burn_amount())
- }
-
- fn pow_required_burn_amount(&self) -> Amount {
- self.ledger
- .recommended_mine_required_burn_amount_with_multiplier(
- self.mine_required_burn_multiplier_bps,
- )
- }
-
pub fn mine_one(&mut self) -> Result<Block> {
self.mine_one_at(now_ms())
}
@@ -1202,7 +1144,6 @@ impl NodeCore {
.map(|block| block.hash.clone())
.context("ledger has no anchor block")?;
let wallet_address = self.wallet.address().to_string();
- let difficulty_bits = self.ledger.current_mine_difficulty_bits();
let needs_cursor = self
.auto_pow_mine_cursor
.as_ref()
@@ -1220,16 +1161,8 @@ impl NodeCore {
.as_ref()
.context("automatic PoW cursor was not initialized")?
.clone();
- let required_burn_amount = self.local_mine_required_burn_amount(
- &wallet_address,
- &anchor,
- cursor.salt,
- difficulty_bits,
- MINE_FINALIZER_FEE,
- )?;
- let outcome = self.ledger.search_mine_with_required_burn(
+ let outcome = self.ledger.search_mine(
wallet_address,
- required_burn_amount,
cursor.salt,
cursor.next_nonce,
AUTO_POW_NONCE_ATTEMPTS_PER_TICK,
@@ -1965,15 +1898,6 @@ fn auto_pow_salt(wallet_address: &str, anchor: &str) -> u64 {
u64::from_be_bytes(bytes)
}
-fn validate_mine_required_burn_multiplier(multiplier_bps: u16) -> Result<()> {
- if !(MIN_MINE_REQUIRED_BURN_MULTIPLIER_BPS..=MAX_MINE_REQUIRED_BURN_MULTIPLIER_BPS)
- .contains(&multiplier_bps)
- {
- bail!("mine required burn multiplier must be between 0.1 and 1.0");
- }
- Ok(())
-}
-
fn converge_fee_by_byte(
fee_per_byte: Amount,
mut build: impl FnMut(Amount) -> Result<Transaction>,
@@ -2037,8 +1961,8 @@ mod tests {
use std::collections::BTreeMap;
use crate::domain::{
- DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS, FinalizerMode, GenesisBurn, Ledger, MICRO_IUNA,
- MINE_FINALIZER_FEE, RECOVERY_BLOCK_DELAY_MS, Transaction, Wallet,
+ FinalizerMode, GenesisBurn, Ledger, MICRO_IUNA, MINE_FINALIZER_FEE,
+ RECOVERY_BLOCK_DELAY_MS, Transaction, Wallet,
};
use super::{GossipEnvelope, NodeConfig, NodeCore};
@@ -2097,7 +2021,6 @@ mod tests {
let Transaction::Mine {
anchor,
recipient,
- required_burn_amount,
difficulty_bits,
..
} = first_mine
@@ -2106,7 +2029,6 @@ mod tests {
};
assert_eq!(anchor, &node.chain().last().unwrap().hash);
assert_eq!(recipient, wallet.address());
- assert!(*required_burn_amount >= crate::domain::MIN_MINE_REQUIRED_BURN);
assert_eq!(
*difficulty_bits,
node.ledger().current_mine_difficulty_bits()
@@ -2227,8 +2149,7 @@ mod tests {
burn_fee: 0,
});
- node.set_pow_mining_settings(true, DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS)
- .unwrap();
+ node.set_pow_mining_enabled(true);
let plan = (1..10_000)
.map(|timestamp| node.prepare_automatic_mining(timestamp))
.find(|plan| plan.pow_mined.is_some())
@@ -2236,10 +2157,7 @@ mod tests {
let mine = plan.pow_mined.expect("PoW should be queued");
assert_eq!(mine.fee(), MINE_FINALIZER_FEE);
- assert_eq!(
- mine.amount(),
- node.status().mining.automatic_pow_required_burn_amount
- );
+ assert_eq!(mine.amount(), crate::domain::MINE_REWARD);
assert_eq!(
node.status().mining.automatic_pow_mine_fee,
MINE_FINALIZER_FEE
@@ -2247,31 +2165,6 @@ mod tests {
}
#[test]
- fn pow_required_burn_multiplier_must_stay_in_configured_range() {
- let wallet = Wallet::from_seed("pow-required-burn-multiplier-wallet");
- let mut node = NodeCore::new(NodeConfig {
- wallet,
- genesis_allocations: BTreeMap::new(),
- vdf_rounds: 10,
- burn_per_block: 0,
- burn_fee: 0,
- });
-
- assert!(node.set_pow_mining_settings(true, 999).is_err());
- node.set_pow_mining_settings(true, 1_000).unwrap();
- assert_eq!(
- node.status().mining.mine_required_burn_multiplier_bps,
- 1_000
- );
- node.set_pow_mining_settings(true, 10_000).unwrap();
- assert_eq!(
- node.status().mining.mine_required_burn_multiplier_bps,
- 10_000
- );
- assert!(node.set_pow_mining_settings(true, 10_001).is_err());
- }
-
- #[test]
fn status_reports_package_version() {
let wallet = Wallet::from_seed("status-version-wallet");
let node = NodeCore::new(NodeConfig {
diff --git a/src/domain.rs b/src/domain.rs
@@ -13,8 +13,6 @@ pub const MICRO_IUNA: Amount = 1_000_000;
pub const BLOCK_REWARD: Amount = 100 * MICRO_IUNA;
pub const MINE_REWARD: Amount = MICRO_IUNA;
pub const MINE_FINALIZER_FEE: Amount = MICRO_IUNA;
-pub const MIN_MINE_REQUIRED_BURN: Amount = MICRO_IUNA / 10;
-pub const MAX_MINE_REQUIRED_BURN: Amount = MINE_REWARD;
pub const DEFAULT_MINE_FEE: Amount = MINE_FINALIZER_FEE;
pub const DEFAULT_TRANSACTION_FEE: Amount = MICRO_IUNA;
pub const DEFAULT_FEE_PER_BYTE: Amount = 1;
@@ -32,8 +30,6 @@ const MINE_MAX_RETARGET_STEP_BITS: u32 = 2;
const MINE_MIN_DIFFICULTY_BITS: u32 = 1;
const MINE_MAX_DIFFICULTY_BITS: u32 = 32;
const MINE_MAX_ANCHOR_AGE_BLOCKS: u64 = MINE_RETARGET_WINDOW_BLOCKS;
-pub const DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS: u16 = 8_000;
-pub const MINE_REQUIRED_BURN_WINDOW_BLOCKS: usize = 10;
pub const MAX_PENDING_TRANSACTIONS: usize = 10_000;
const MAX_ORPHAN_TRANSACTIONS: usize = 1_024;
const MAX_BLOCK_TRANSACTIONS: usize = 1_000;
@@ -157,7 +153,6 @@ pub enum Transaction {
},
Mine {
recipient: String,
- required_burn_amount: Amount,
anchor: String,
#[serde(default)]
salt: u64,
@@ -294,10 +289,7 @@ impl Transaction {
outputs.first().map(|output| output.amount).unwrap_or(0)
}
Self::Burn { amount, .. } => *amount,
- Self::Mine {
- required_burn_amount,
- ..
- } => *required_burn_amount,
+ Self::Mine { .. } => MINE_REWARD,
Self::BurnClaim { .. } => 0,
}
}
@@ -331,13 +323,6 @@ impl Transaction {
matches!(self, Self::Burn { .. })
}
- fn burn_amount(&self) -> Amount {
- match self {
- Self::Burn { amount, .. } => *amount,
- Self::Transfer { .. } | Self::Mine { .. } | Self::BurnClaim { .. } => 0,
- }
- }
-
pub fn canonical(&self) -> String {
format!("{}:{}", self.signing_payload(), self.signature())
}
@@ -380,20 +365,12 @@ impl Transaction {
.canonical(),
Self::Mine {
recipient,
- required_burn_amount,
anchor,
salt,
nonce,
difficulty_bits,
..
- } => mine_payload(
- recipient,
- *required_burn_amount,
- anchor,
- *salt,
- *nonce,
- *difficulty_bits,
- ),
+ } => mine_payload(recipient, anchor, *salt, *nonce, *difficulty_bits),
Self::BurnClaim { burn, seen, .. } => burn_claim_payload(burn, seen),
}
}
@@ -401,7 +378,6 @@ impl Transaction {
fn verify_signature(&self) -> Result<()> {
if let Self::Mine {
recipient,
- required_burn_amount,
anchor,
salt,
nonce,
@@ -411,28 +387,15 @@ impl Transaction {
} = self
{
let expected = if let Some(proof_header) = proof_header {
- let header = stratum_mine_header_bytes(
- recipient,
- *required_burn_amount,
- anchor,
- *salt,
- *nonce,
- *difficulty_bits,
- )?;
+ let header =
+ stratum_mine_header_bytes(recipient, anchor, *salt, *nonce, *difficulty_bits)?;
let expected_header = hex_encode(header);
if *proof_header != expected_header {
bail!("mine transaction proof header is invalid");
}
stratum_mine_signature(&header)
} else {
- mine_signature(
- recipient,
- *required_burn_amount,
- anchor,
- *salt,
- *nonce,
- *difficulty_bits,
- )
+ mine_signature(recipient, anchor, *salt, *nonce, *difficulty_bits)
};
if *signature != expected {
bail!("mine transaction proof hash is invalid");
@@ -492,13 +455,9 @@ impl Transaction {
match self {
Self::Transfer { outputs, .. } => outputs.clone(),
Self::Burn { change, .. } => change.clone(),
- Self::Mine {
- recipient,
- required_burn_amount,
- ..
- } => vec![TxOutput {
+ Self::Mine { recipient, .. } => vec![TxOutput {
address: recipient.clone(),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
}],
Self::BurnClaim { .. } => Vec::new(),
}
@@ -639,20 +598,16 @@ fn canonical_outputs(outputs: &[TxOutput]) -> String {
fn mine_payload(
recipient: &str,
- required_burn_amount: Amount,
anchor: &str,
salt: u64,
nonce: u64,
difficulty_bits: u32,
) -> String {
- format!(
- "iuna-mine:{recipient}:{required_burn_amount}:{anchor}:{salt}:{nonce}:{difficulty_bits}"
- )
+ format!("iuna-mine:{recipient}:{anchor}:{salt}:{nonce}:{difficulty_bits}")
}
fn mine_signature(
recipient: &str,
- required_burn_amount: Amount,
anchor: &str,
salt: u64,
nonce: u64,
@@ -660,7 +615,6 @@ fn mine_signature(
) -> String {
hex_hash(mine_payload(
recipient,
- required_burn_amount,
anchor,
salt,
nonce,
@@ -719,7 +673,6 @@ const STRATUM_MINE_NTIME: [u8; 4] = [0, 0, 0, 0];
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct StratumMineTemplate {
pub recipient: String,
- pub required_burn_amount: Amount,
pub anchor: String,
pub salt: u64,
pub difficulty_bits: u32,
@@ -757,33 +710,22 @@ fn unpack_stratum_nonce(nonce: u64) -> ([u8; 4], [u8; 4]) {
fn stratum_coinbase_prefix(
recipient: &str,
- required_burn_amount: Amount,
anchor: &str,
salt: u64,
difficulty_bits: u32,
) -> Vec<u8> {
- format!(
- "iuna-stratum-mine:{recipient}:{required_burn_amount}:{anchor}:{salt}:{difficulty_bits}:"
- )
- .into_bytes()
+ format!("iuna-stratum-mine:{recipient}:{anchor}:{salt}:{difficulty_bits}:").into_bytes()
}
fn stratum_coinbase_bytes(
recipient: &str,
- required_burn_amount: Amount,
anchor: &str,
salt: u64,
nonce: u64,
difficulty_bits: u32,
) -> Vec<u8> {
let (extranonce2, _) = unpack_stratum_nonce(nonce);
- let mut coinbase = stratum_coinbase_prefix(
- recipient,
- required_burn_amount,
- anchor,
- salt,
- difficulty_bits,
- );
+ let mut coinbase = stratum_coinbase_prefix(recipient, anchor, salt, difficulty_bits);
coinbase.extend_from_slice(&[0, 0, 0, 0]);
coinbase.extend_from_slice(&extranonce2);
coinbase
@@ -797,7 +739,6 @@ fn double_sha256(bytes: &[u8]) -> [u8; 32] {
fn stratum_mine_header_bytes(
recipient: &str,
- required_burn_amount: Amount,
anchor: &str,
salt: u64,
nonce: u64,
@@ -810,7 +751,6 @@ fn stratum_mine_header_bytes(
header[4..36].copy_from_slice(&anchor_bytes);
let merkle_root = double_sha256(&stratum_coinbase_bytes(
recipient,
- required_burn_amount,
anchor,
salt,
nonce,
@@ -832,7 +772,6 @@ fn stratum_mine_signature(header: &[u8; 80]) -> String {
fn stratum_mine_template(
recipient: impl Into<String>,
- required_burn_amount: Amount,
anchor: &str,
salt: u64,
difficulty_bits: u32,
@@ -840,22 +779,14 @@ fn stratum_mine_template(
let recipient = recipient.into();
validate_address(&recipient, "mine recipient")?;
validate_hash(anchor, "mine transaction anchor")?;
- validate_mine_required_burn_amount(required_burn_amount)?;
let anchor_bytes =
decode_hex_array::<HASH_BYTES>(anchor).context("mine transaction anchor is not hex")?;
Ok(StratumMineTemplate {
recipient: recipient.clone(),
- required_burn_amount,
anchor: anchor.to_string(),
salt,
difficulty_bits,
- coinbase_prefix: stratum_coinbase_prefix(
- &recipient,
- required_burn_amount,
- anchor,
- salt,
- difficulty_bits,
- ),
+ coinbase_prefix: stratum_coinbase_prefix(&recipient, anchor, salt, difficulty_bits),
version_hex: hex_encode(STRATUM_MINE_VERSION),
prev_hash_hex: hex_encode(anchor_bytes),
nbits_hex: hex_encode(difficulty_bits.to_le_bytes()),
@@ -1793,34 +1724,6 @@ impl Ledger {
self.mine_difficulty_bits_for_anchor_height(self.tip().height)
}
- pub fn recommended_mine_required_burn_amount(&self) -> Amount {
- self.recommended_mine_required_burn_amount_with_multiplier(
- DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS,
- )
- }
-
- pub fn recommended_mine_required_burn_amount_with_multiplier(
- &self,
- multiplier_bps: u16,
- ) -> Amount {
- let Some(min_burn) = self
- .chain
- .iter()
- .rev()
- .filter(|block| block.height > 0)
- .take(MINE_REQUIRED_BURN_WINDOW_BLOCKS)
- .map(block_burn_amount)
- .min()
- else {
- return MIN_MINE_REQUIRED_BURN;
- };
- let scaled = u128::from(min_burn)
- .saturating_mul(u128::from(multiplier_bps))
- .saturating_div(10_000)
- .min(u128::from(Amount::MAX)) as Amount;
- scaled.clamp(MIN_MINE_REQUIRED_BURN, MAX_MINE_REQUIRED_BURN)
- }
-
pub fn mine_difficulty_bits_at_height(&self, height: u64) -> u32 {
self.mine_difficulty_bits_for_anchor_height(height.min(self.tip().height))
}
@@ -1970,35 +1873,18 @@ impl Ledger {
}
pub fn build_mine(&self, recipient: impl Into<String>) -> Result<Transaction> {
- self.build_mine_with_required_burn(recipient, self.recommended_mine_required_burn_amount())
- }
-
- pub fn build_mine_with_required_burn(
- &self,
- recipient: impl Into<String>,
- required_burn_amount: Amount,
- ) -> Result<Transaction> {
let recipient = recipient.into();
validate_address(&recipient, "mine recipient")?;
- validate_mine_required_burn_amount(required_burn_amount)?;
let anchor = self.tip().hash.clone();
let salt = 1;
let difficulty_bits = self.current_mine_difficulty_bits();
for nonce in 0..u64::MAX {
- let signature = mine_signature(
- &recipient,
- required_burn_amount,
- &anchor,
- salt,
- nonce,
- difficulty_bits,
- );
+ let signature = mine_signature(&recipient, &anchor, salt, nonce, difficulty_bits);
if !hash_meets_difficulty(&signature, difficulty_bits) {
continue;
}
let transaction = Transaction::Mine {
recipient: recipient.clone(),
- required_burn_amount,
anchor: anchor.clone(),
salt,
nonce,
@@ -2015,36 +1901,26 @@ impl Ledger {
bail!("could not find valid mine proof");
}
- pub fn search_mine_with_required_burn(
+ pub fn search_mine(
&self,
recipient: impl Into<String>,
- required_burn_amount: Amount,
salt: u64,
start_nonce: u64,
max_attempts: u64,
) -> Result<MineSearchOutcome> {
let recipient = recipient.into();
validate_address(&recipient, "mine recipient")?;
- validate_mine_required_burn_amount(required_burn_amount)?;
let anchor = self.tip().hash.clone();
let difficulty_bits = self.current_mine_difficulty_bits();
let mut attempts = 0_u64;
let mut nonce = start_nonce;
while attempts < max_attempts {
- let signature = mine_signature(
- &recipient,
- required_burn_amount,
- &anchor,
- salt,
- nonce,
- difficulty_bits,
- );
+ let signature = mine_signature(&recipient, &anchor, salt, nonce, difficulty_bits);
attempts = attempts.saturating_add(1);
let next_nonce = nonce.checked_add(1).unwrap_or(0);
if hash_meets_difficulty(&signature, difficulty_bits) {
let transaction = Transaction::Mine {
recipient: recipient.clone(),
- required_burn_amount,
anchor: anchor.clone(),
salt,
nonce,
@@ -2073,18 +1949,11 @@ impl Ledger {
pub fn stratum_mine_template(
&self,
recipient: impl Into<String>,
- required_burn_amount: Amount,
anchor: impl AsRef<str>,
salt: u64,
difficulty_bits: u32,
) -> Result<StratumMineTemplate> {
- stratum_mine_template(
- recipient,
- required_burn_amount,
- anchor.as_ref(),
- salt,
- difficulty_bits,
- )
+ stratum_mine_template(recipient, anchor.as_ref(), salt, difficulty_bits)
}
pub fn build_stratum_mine(
@@ -2095,7 +1964,6 @@ impl Ledger {
let nonce = pack_stratum_nonce(share.extranonce2, share.header_nonce);
let header = stratum_mine_header_bytes(
&template.recipient,
- template.required_burn_amount,
&template.anchor,
template.salt,
nonce,
@@ -2103,7 +1971,6 @@ impl Ledger {
)?;
let transaction = Transaction::Mine {
recipient: template.recipient,
- required_burn_amount: template.required_burn_amount,
anchor: template.anchor,
salt: template.salt,
nonce,
@@ -2179,7 +2046,6 @@ impl Ledger {
let transactions = self.select_block_transactions()?;
ensure_block_has_burn(&transactions)?;
- ensure_mine_actions_have_required_burns(&transactions)?;
let tip = self.tip();
let prev_hash = tip.hash.clone();
@@ -2220,7 +2086,6 @@ impl Ledger {
let transactions = self.select_recovery_block_transactions(miner)?;
ensure_block_has_burn(&transactions)?;
ensure_block_has_burn_from(&transactions, miner)?;
- ensure_mine_actions_have_required_burns(&transactions)?;
let tip = self.tip();
let prev_hash = tip.hash.clone();
@@ -2386,7 +2251,6 @@ impl Ledger {
bail!("block exceeds max block size");
}
ensure_block_has_burn(&block.transactions)?;
- ensure_mine_actions_have_required_burns(&block.transactions)?;
self.ensure_due_burn_claims_are_included(block.height, &block.transactions)?;
match block.finalizer_mode {
FinalizerMode::Ticket => {
@@ -2515,7 +2379,6 @@ impl Ledger {
let mut utxos = self.utxos.clone();
let mut remaining = self.valid_pending_transactions();
let mut selected = Vec::new();
- let mut selected_burn_amount = 0_u64;
for tx in self.due_required_claimed_burns(self.tip().height + 1)? {
remaining.retain(|pending| pending.signature() != tx.signature());
@@ -2525,9 +2388,6 @@ impl Ledger {
bail!("due claimed burns exceed max block size");
}
apply_transaction(&tx, &mut utxos)?;
- selected_burn_amount = selected_burn_amount
- .checked_add(tx.burn_amount())
- .context("selected block burns overflow")?;
selected.push(tx);
}
@@ -2549,21 +2409,13 @@ impl Ledger {
candidate.push(tx.clone());
if estimated_block_size_bytes(&candidate)? <= self.launch_profile.max_block_bytes {
apply_transaction(&tx, &mut utxos)?;
- selected_burn_amount = selected_burn_amount
- .checked_add(tx.burn_amount())
- .context("selected block burns overflow")?;
selected.push(tx);
}
}
}
while selected.len() < self.launch_profile.max_block_transactions {
- let Some(index) = best_selectable_transaction_index_for_burn_amount(
- &remaining,
- &utxos,
- None,
- selected_burn_amount,
- ) else {
+ let Some(index) = best_selectable_transaction_index(&remaining, &utxos, None) else {
break;
};
let tx = remaining.remove(index);
@@ -2571,9 +2423,6 @@ impl Ledger {
candidate.push(tx.clone());
if estimated_block_size_bytes(&candidate)? <= self.launch_profile.max_block_bytes {
apply_transaction(&tx, &mut utxos)?;
- selected_burn_amount = selected_burn_amount
- .checked_add(tx.burn_amount())
- .context("selected block burns overflow")?;
selected.push(tx);
}
}
@@ -2752,7 +2601,6 @@ impl Ledger {
}
Transaction::Mine {
recipient,
- required_burn_amount,
anchor,
difficulty_bits,
proof_header,
@@ -2760,7 +2608,6 @@ impl Ledger {
..
} => {
validate_address(recipient, "mine recipient")?;
- validate_mine_required_burn_amount(*required_burn_amount)?;
validate_hash(anchor, "mine transaction anchor")?;
validate_hash(signature, "mine transaction proof hash")?;
if let Some(proof_header) = proof_header {
@@ -3279,38 +3126,6 @@ fn ensure_block_has_burn_from(transactions: &[Transaction], miner: &str) -> Resu
Ok(())
}
-fn block_burn_amount(block: &Block) -> Amount {
- transactions_burn_amount(&block.transactions).unwrap_or(Amount::MAX)
-}
-
-fn transactions_burn_amount(transactions: &[Transaction]) -> Result<Amount> {
- transactions.iter().try_fold(0_u64, |total, tx| {
- total
- .checked_add(tx.burn_amount())
- .context("burns overflow")
- })
-}
-
-fn ensure_mine_actions_have_required_burns(transactions: &[Transaction]) -> Result<()> {
- let burn_amount = transactions_burn_amount(transactions)?;
- for transaction in transactions {
- if let Transaction::Mine {
- required_burn_amount,
- ..
- } = transaction
- {
- if burn_amount < *required_burn_amount {
- bail!(
- "mine transaction requires {} burn but block only includes {}",
- required_burn_amount,
- burn_amount
- );
- }
- }
- }
- Ok(())
-}
-
fn ensure_valid_recovery_block(block: &Block, parent: &Block) -> Result<()> {
if block.finalizer_rank != 0 {
bail!("recovery block finalizer rank must be 0");
@@ -3338,23 +3153,13 @@ fn best_selectable_transaction_index(
utxos: &BTreeMap<OutPoint, TxOutput>,
required_kind: Option<TransactionKind>,
) -> Option<usize> {
- best_selectable_transaction_index_for_burn_amount(
- transactions,
- utxos,
- required_kind,
- Amount::MAX,
- )
-}
-
-fn best_selectable_burn_from_index(
- transactions: &[Transaction],
- utxos: &BTreeMap<OutPoint, TxOutput>,
- owner: &str,
-) -> Option<usize> {
transactions
.iter()
.enumerate()
- .filter(|(_, tx)| tx.is_burn() && tx.sender() == owner)
+ .filter(|(_, tx)| match required_kind {
+ Some(TransactionKind::Burn) => tx.is_burn(),
+ None => true,
+ })
.filter(|(_, tx)| {
let mut utxos = utxos.clone();
apply_transaction(tx, &mut utxos).is_ok()
@@ -3363,33 +3168,21 @@ fn best_selectable_burn_from_index(
fee_rate_key(left)
.cmp(&fee_rate_key(right))
.then_with(|| left.fee().cmp(&right.fee()))
+ .then_with(|| left.is_burn().cmp(&right.is_burn()))
.then_with(|| right.signature().cmp(left.signature()))
})
.map(|(index, _)| index)
}
-fn best_selectable_transaction_index_for_burn_amount(
+fn best_selectable_burn_from_index(
transactions: &[Transaction],
utxos: &BTreeMap<OutPoint, TxOutput>,
- required_kind: Option<TransactionKind>,
- selected_burn_amount: Amount,
+ owner: &str,
) -> Option<usize> {
transactions
.iter()
.enumerate()
- .filter(|(_, tx)| match required_kind {
- Some(TransactionKind::Burn) => tx.is_burn(),
- None => true,
- })
- .filter(|(_, tx)| {
- !matches!(
- tx,
- Transaction::Mine {
- required_burn_amount,
- ..
- } if *required_burn_amount > selected_burn_amount
- )
- })
+ .filter(|(_, tx)| tx.is_burn() && tx.sender() == owner)
.filter(|(_, tx)| {
let mut utxos = utxos.clone();
apply_transaction(tx, &mut utxos).is_ok()
@@ -3398,7 +3191,6 @@ fn best_selectable_transaction_index_for_burn_amount(
fee_rate_key(left)
.cmp(&fee_rate_key(right))
.then_with(|| left.fee().cmp(&right.fee()))
- .then_with(|| left.is_burn().cmp(&right.is_burn()))
.then_with(|| right.signature().cmp(left.signature()))
})
.map(|(index, _)| index)
@@ -3464,17 +3256,6 @@ fn validate_hash(hash: &str, label: &str) -> Result<()> {
Ok(())
}
-fn validate_mine_required_burn_amount(amount: Amount) -> Result<()> {
- if !(MIN_MINE_REQUIRED_BURN..=MAX_MINE_REQUIRED_BURN).contains(&amount) {
- bail!(
- "mine required burn amount must be between {} and {}",
- MIN_MINE_REQUIRED_BURN,
- MAX_MINE_REQUIRED_BURN
- );
- }
- Ok(())
-}
-
fn validate_signature(signature: &str, label: &str) -> Result<()> {
decode_hex_array::<SIGNATURE_BYTES>(signature).with_context(|| format!("invalid {label}"))?;
Ok(())
@@ -3526,7 +3307,6 @@ fn canonical_transaction_size_bytes(transaction: &Transaction) -> usize {
}
Transaction::Mine {
recipient,
- required_burn_amount,
anchor,
salt,
nonce,
@@ -3535,7 +3315,6 @@ fn canonical_transaction_size_bytes(transaction: &Transaction) -> usize {
signature,
} => {
1 + address_size_bytes(recipient)
- + compact_len(u128::from(*required_burn_amount))
+ hash_size_bytes(anchor)
+ compact_len(u128::from(*salt))
+ compact_len(u128::from(*nonce))
@@ -3708,14 +3487,10 @@ fn apply_transaction(
) -> Result<()> {
transaction.verify_signature()?;
match transaction {
- Transaction::Mine {
- recipient,
- required_burn_amount,
- ..
- } => {
+ Transaction::Mine { recipient, .. } => {
let output = TxOutput {
address: recipient.clone(),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
};
ensure_outputs_do_not_overflow(utxos, std::slice::from_ref(&output))?;
utxos.insert(
@@ -4286,27 +4061,17 @@ mod tests {
block
}
- fn mine_with_required_burn(
- ledger: &Ledger,
- recipient: &str,
- required_burn_amount: Amount,
- ) -> Transaction {
+ const TEST_BURN_AMOUNT: Amount = MICRO_IUNA / 10;
+
+ fn unsigned_mine(ledger: &Ledger, recipient: &str) -> Transaction {
let anchor = ledger.tip().hash.clone();
let difficulty_bits = ledger.current_mine_difficulty_bits();
for nonce in 0..u64::MAX {
let salt = 1;
- let signature = mine_signature(
- recipient,
- required_burn_amount,
- &anchor,
- salt,
- nonce,
- difficulty_bits,
- );
+ let signature = mine_signature(recipient, &anchor, salt, nonce, difficulty_bits);
if hash_meets_difficulty(&signature, difficulty_bits) {
return Transaction::Mine {
recipient: recipient.to_string(),
- required_burn_amount,
anchor,
salt,
nonce,
@@ -4364,9 +4129,7 @@ mod tests {
})
})
.expect("expected an eligible finalizer wallet");
- let burn = ledger
- .build_burn(wallet, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let burn = ledger.build_burn(wallet, TEST_BURN_AMOUNT, 0).unwrap();
ledger.submit_transaction(burn).unwrap();
let prepared = ledger
.prepare_next_block(wallet.address(), ledger.tip().timestamp_ms + 1)
@@ -4604,9 +4367,7 @@ mod tests {
let alice = Wallet::from_seed("bounded-mine-search-alice");
let ledger = Ledger::new(BTreeMap::new(), 1);
- let outcome = ledger
- .search_mine_with_required_burn(alice.address(), MIN_MINE_REQUIRED_BURN, 1, 0, 0)
- .unwrap();
+ let outcome = ledger.search_mine(alice.address(), 1, 0, 0).unwrap();
assert!(outcome.transaction.is_none());
assert_eq!(outcome.next_nonce, 0);
@@ -5002,32 +4763,13 @@ mod tests {
}
#[test]
- fn mine_required_burn_amount_must_be_in_protocol_range() {
- let alice = Wallet::from_seed("mine-required-burn-range-alice");
- let ledger = ledger_with_allocation(&alice, MICRO_IUNA);
-
- let low = ledger
- .build_mine_with_required_burn(alice.address(), MIN_MINE_REQUIRED_BURN - 1)
- .unwrap_err();
- let high = ledger
- .build_mine_with_required_burn(alice.address(), MAX_MINE_REQUIRED_BURN + 1)
- .unwrap_err();
-
- assert!(format!("{low:#}").contains("required burn amount"));
- assert!(format!("{high:#}").contains("required burn amount"));
- }
-
- #[test]
- fn mine_required_burn_amount_is_bound_to_proof_hash() {
- let alice = Wallet::from_seed("mine-required-burn-proof-alice");
+ fn mine_recipient_is_bound_to_proof_hash() {
+ let alice = Wallet::from_seed("mine-proof-alice");
+ let bob = Wallet::from_seed("mine-proof-bob");
let mut ledger = ledger_with_allocation(&alice, MICRO_IUNA);
- let mut forged = mine_with_required_burn(&ledger, alice.address(), MIN_MINE_REQUIRED_BURN);
- if let Transaction::Mine {
- required_burn_amount,
- ..
- } = &mut forged
- {
- *required_burn_amount = required_burn_amount.saturating_add(1);
+ let mut forged = unsigned_mine(&ledger, alice.address());
+ if let Transaction::Mine { recipient, .. } = &mut forged {
+ *recipient = bob.address().to_string();
}
let error = ledger.submit_transaction(forged).unwrap_err();
@@ -5036,69 +4778,18 @@ mod tests {
}
#[test]
- fn mine_action_uses_required_burn_reward_and_fixed_finalizer_fee() {
- let alice = Wallet::from_seed("mine-required-burn-reward-alice");
+ fn mine_action_uses_fixed_reward_and_fixed_finalizer_fee() {
+ let alice = Wallet::from_seed("mine-fixed-reward-alice");
let mut ledger = ledger_with_allocation(&alice, MICRO_IUNA);
- let mine = ledger
- .build_mine_with_required_burn(alice.address(), MIN_MINE_REQUIRED_BURN)
- .unwrap();
+ let mine = ledger.build_mine(alice.address()).unwrap();
- assert_eq!(mine.amount(), MIN_MINE_REQUIRED_BURN);
+ assert_eq!(mine.amount(), MINE_REWARD);
assert_eq!(mine.fee(), MINE_FINALIZER_FEE);
assert!(ledger.submit_transaction(mine).unwrap());
}
#[test]
- fn recommended_mine_required_burn_uses_multiplier_times_recent_minimum() {
- let alice = Wallet::from_seed("mine-required-burn-policy-alice");
- let mut ledger = ledger_with_allocation(&alice, 10 * MICRO_IUNA);
-
- assert_eq!(
- ledger.recommended_mine_required_burn_amount_with_multiplier(8_000),
- MIN_MINE_REQUIRED_BURN
- );
-
- for amount in [MICRO_IUNA, MICRO_IUNA / 2, 3 * MICRO_IUNA / 2] {
- let burn = ledger.build_burn(&alice, amount, 0).unwrap();
- ledger.submit_transaction(burn).unwrap();
- let block = ledger.mine_next_block(&alice, ledger.height() + 1).unwrap();
- ledger.apply_locally_mined_block(block).unwrap();
- }
-
- assert_eq!(
- ledger.recommended_mine_required_burn_amount_with_multiplier(8_000),
- 400_000
- );
- assert_eq!(
- ledger.recommended_mine_required_burn_amount_with_multiplier(100),
- MIN_MINE_REQUIRED_BURN
- );
- assert_eq!(
- ledger.recommended_mine_required_burn_amount_with_multiplier(10_000),
- MICRO_IUNA / 2
- );
- }
-
- #[test]
- fn recommended_mine_required_burn_uses_last_ten_non_genesis_blocks() {
- let alice = Wallet::from_seed("mine-required-burn-window-alice");
- let mut ledger = ledger_with_allocation(&alice, 20 * MICRO_IUNA);
-
- for amount in std::iter::once(MIN_MINE_REQUIRED_BURN).chain([MICRO_IUNA; 10]) {
- let burn = ledger.build_burn(&alice, amount, 0).unwrap();
- ledger.submit_transaction(burn).unwrap();
- let block = ledger.mine_next_block(&alice, ledger.height() + 1).unwrap();
- ledger.apply_locally_mined_block(block).unwrap();
- }
-
- assert_eq!(
- ledger.recommended_mine_required_burn_amount_with_multiplier(10_000),
- MICRO_IUNA
- );
- }
-
- #[test]
fn burn_claim_requires_recent_finalizer_quorum() {
let finalizers = (0..5)
.map(|index| Wallet::from_seed(&format!("burn-claim-quorum-finalizer-{index}")))
@@ -5108,9 +4799,7 @@ mod tests {
mine_until_recent_finalizers(&mut ledger, &finalizers, BURN_CLAIM_SEEN_QUORUM);
assert!(recent_unique_finalizer_count(&ledger) >= BURN_CLAIM_SEEN_QUORUM);
- let burn = ledger
- .build_burn(&burner, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let burn = ledger.build_burn(&burner, TEST_BURN_AMOUNT, 0).unwrap();
let seen =
recent_burn_seen_attestations(&ledger, &finalizers, &burn, BURN_CLAIM_SEEN_QUORUM - 1);
@@ -5128,9 +4817,7 @@ mod tests {
let mut ledger = ledger_with_finalizers_and_burner(&finalizers, &burner);
mine_until_recent_finalizers(&mut ledger, &finalizers, BURN_CLAIM_SEEN_QUORUM);
- let burn = ledger
- .build_burn(&burner, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let burn = ledger.build_burn(&burner, TEST_BURN_AMOUNT, 0).unwrap();
let mut seen =
recent_burn_seen_attestations(&ledger, &finalizers, &burn, BURN_CLAIM_SEEN_QUORUM);
seen[0].signature = "00".repeat(SIGNATURE_BYTES);
@@ -5149,9 +4836,7 @@ mod tests {
let burner = Wallet::from_seed("burn-claim-due-burner");
let mut ledger = ledger_with_finalizers_and_burner(&finalizers, &burner);
mine_until_recent_finalizers(&mut ledger, &finalizers, BURN_CLAIM_SEEN_QUORUM);
- let burn = ledger
- .build_burn(&burner, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let burn = ledger.build_burn(&burner, TEST_BURN_AMOUNT, 0).unwrap();
let burn_signature = burn.signature().to_string();
confirm_burn_claim(&mut ledger, &finalizers, burn);
@@ -5162,9 +4847,7 @@ mod tests {
let leader = ledger.expected_leader_for_next_block().unwrap();
let wallet = wallet_for_address(&finalizers, &leader);
- let filler_burn = ledger
- .build_burn(wallet, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let filler_burn = ledger.build_burn(wallet, TEST_BURN_AMOUNT, 0).unwrap();
ledger.submit_transaction(filler_burn.clone()).unwrap();
let mut prepared = ledger
.prepare_next_block(wallet.address(), ledger.tip().timestamp_ms + 1)
@@ -5202,9 +4885,7 @@ mod tests {
let burner = Wallet::from_seed("burn-claim-select-burner");
let mut ledger = ledger_with_finalizers_and_burner(&finalizers, &burner);
mine_until_recent_finalizers(&mut ledger, &finalizers, BURN_CLAIM_SEEN_QUORUM);
- let burn = ledger
- .build_burn(&burner, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let burn = ledger.build_burn(&burner, TEST_BURN_AMOUNT, 0).unwrap();
let burn_signature = burn.signature().to_string();
confirm_burn_claim(&mut ledger, &finalizers, burn);
@@ -5236,9 +4917,7 @@ mod tests {
let recipient = Wallet::from_seed("burn-claim-invalid-recipient");
let mut ledger = ledger_with_finalizers_and_burner(&finalizers, &burner);
mine_until_recent_finalizers(&mut ledger, &finalizers, BURN_CLAIM_SEEN_QUORUM);
- let burn = ledger
- .build_burn(&burner, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let burn = ledger.build_burn(&burner, TEST_BURN_AMOUNT, 0).unwrap();
let burn_signature = burn.signature().to_string();
let burn_input = burn.inputs().first().unwrap().outpoint.clone();
@@ -5255,9 +4934,7 @@ mod tests {
let leader = ledger.expected_leader_for_next_block().unwrap();
let wallet = wallet_for_address(&finalizers, &leader);
- let filler_burn = ledger
- .build_burn(wallet, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let filler_burn = ledger.build_burn(wallet, TEST_BURN_AMOUNT, 0).unwrap();
ledger.submit_transaction(filler_burn).unwrap();
let block = ledger
.prepare_next_block(wallet.address(), ledger.tip().timestamp_ms + 1)
@@ -5274,47 +4951,20 @@ mod tests {
}
#[test]
- fn block_with_mine_action_requires_enough_burn_amount() {
- let alice = Wallet::from_seed("mine-required-burn-block-alice");
- let mut ledger = ledger_with_allocation(&alice, 10 * MICRO_IUNA);
-
- let burn = ledger
- .build_burn(&alice, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
- ledger.submit_transaction(burn.clone()).unwrap();
- let mine = ledger
- .build_mine_with_required_burn(alice.address(), MAX_MINE_REQUIRED_BURN)
- .unwrap();
- let mut prepared = ledger.prepare_next_block(alice.address(), 1).unwrap();
- prepared.reward = prepared.reward.checked_add(mine.fee()).unwrap();
- prepared.transactions.push(mine);
- let vdf_output = run_vdf(prepared.vdf_seed(), prepared.vdf_rounds());
- let block = prepared.finish(&alice, vdf_output);
-
- let error = ledger.apply_block(block).unwrap_err();
-
- assert!(format!("{error:#}").contains("requires"));
- }
-
- #[test]
- fn block_selection_includes_mine_action_when_cumulative_burns_meet_requirement() {
- let alice = Wallet::from_seed("mine-cumulative-burn-alice");
+ fn block_selection_includes_mine_action_after_required_block_burn() {
+ let alice = Wallet::from_seed("mine-fixed-reward-select-alice");
let mut ledger = ledger_with_allocation(&alice, 10 * MICRO_IUNA);
- for _ in 0..2 {
- let burn = ledger.build_burn(&alice, MICRO_IUNA / 2, 0).unwrap();
- ledger.submit_transaction(burn).unwrap();
- }
- let mine = ledger
- .build_mine_with_required_burn(alice.address(), MICRO_IUNA)
- .unwrap();
+ let burn = ledger.build_burn(&alice, TEST_BURN_AMOUNT, 0).unwrap();
+ ledger.submit_transaction(burn).unwrap();
+ let mine = ledger.build_mine(alice.address()).unwrap();
ledger.submit_transaction(mine.clone()).unwrap();
let block = ledger.mine_next_block(&alice, 1).unwrap();
assert_eq!(
block.transactions.iter().filter(|tx| tx.is_burn()).count(),
- 2
+ 1
);
assert!(
block
@@ -5346,45 +4996,12 @@ mod tests {
}
#[test]
- fn block_selection_keeps_mine_action_pending_when_required_burn_is_not_met() {
- let alice = Wallet::from_seed("mine-required-burn-pending-alice");
- let mut ledger = ledger_with_allocation(&alice, 10 * MICRO_IUNA);
-
- let burn = ledger
- .build_burn(&alice, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
- ledger.submit_transaction(burn).unwrap();
- let mine = ledger
- .build_mine_with_required_burn(alice.address(), MAX_MINE_REQUIRED_BURN)
- .unwrap();
- ledger.submit_transaction(mine.clone()).unwrap();
-
- let block = ledger.mine_next_block(&alice, 1).unwrap();
-
- assert!(block.transactions.iter().any(Transaction::is_burn));
- assert!(
- !block
- .transactions
- .iter()
- .any(|tx| tx.signature() == mine.signature())
- );
- assert!(
- ledger
- .pending()
- .iter()
- .any(|tx| tx.signature() == mine.signature())
- );
- }
-
- #[test]
fn pending_mine_outputs_are_not_spendable_until_confirmed() {
let alice = Wallet::from_seed("pending-mine-spend-alice");
let bob = Wallet::from_seed("pending-mine-spend-bob");
let mut ledger = ledger_with_allocation(&alice, 10 * MICRO_IUNA);
- let mine = ledger
- .build_mine_with_required_burn(alice.address(), MIN_MINE_REQUIRED_BURN)
- .unwrap();
+ let mine = ledger.build_mine(alice.address()).unwrap();
let mine_outpoint = OutPoint {
txid: mine.signature().to_string(),
index: 0,
@@ -5402,16 +5019,14 @@ mod tests {
.build_transfer_with_inputs(
&alice,
bob.address(),
- MIN_MINE_REQUIRED_BURN,
+ TEST_BURN_AMOUNT,
0,
std::slice::from_ref(&mine_outpoint),
)
.unwrap_err();
assert!(format!("{pending_error:#}").contains("not spendable"));
- let burn = ledger
- .build_burn(&alice, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let burn = ledger.build_burn(&alice, TEST_BURN_AMOUNT, 0).unwrap();
ledger.submit_transaction(burn).unwrap();
let block = ledger.mine_next_block(&alice, 1).unwrap();
assert!(
@@ -5433,7 +5048,7 @@ mod tests {
.build_transfer_with_inputs(
&alice,
bob.address(),
- MIN_MINE_REQUIRED_BURN,
+ TEST_BURN_AMOUNT,
0,
std::slice::from_ref(&mine_outpoint),
)
@@ -5445,18 +5060,14 @@ mod tests {
let alice = Wallet::from_seed("pending-mine-burn-alice");
let mut ledger = ledger_with_allocation(&alice, 10 * MICRO_IUNA);
- let mine = ledger
- .build_mine_with_required_burn(alice.address(), MIN_MINE_REQUIRED_BURN)
- .unwrap();
+ let mine = ledger.build_mine(alice.address()).unwrap();
let mine_outpoint = OutPoint {
txid: mine.signature().to_string(),
index: 0,
};
ledger.submit_transaction(mine).unwrap();
- let burn = ledger
- .build_burn(&alice, MIN_MINE_REQUIRED_BURN, 0)
- .unwrap();
+ let burn = ledger.build_burn(&alice, TEST_BURN_AMOUNT, 0).unwrap();
let Transaction::Burn { inputs, .. } = &burn else {
panic!("expected burn transaction");
@@ -5577,13 +5188,7 @@ mod tests {
let anchor = ledger.tip().hash.clone();
let difficulty_bits = ledger.current_mine_difficulty_bits();
let template = ledger
- .stratum_mine_template(
- alice.address(),
- MINE_FINALIZER_FEE,
- anchor,
- 1,
- difficulty_bits,
- )
+ .stratum_mine_template(alice.address(), anchor, 1, difficulty_bits)
.unwrap();
let mut accepted = None;
@@ -5623,13 +5228,7 @@ mod tests {
for salt in [1, 2] {
let template = ledger
- .stratum_mine_template(
- alice.address(),
- MINE_FINALIZER_FEE,
- anchor.clone(),
- salt,
- difficulty_bits,
- )
+ .stratum_mine_template(alice.address(), anchor.clone(), salt, difficulty_bits)
.unwrap();
let mut accepted = None;
for nonce in 0_u32..50_000 {
diff --git a/src/main.rs b/src/main.rs
@@ -87,10 +87,7 @@ async fn main() -> Result<()> {
initial_burn_fee,
),
};
- node_core.set_pow_mining_settings(
- ui_config.pow_mining_enabled,
- ui_config.mine_required_burn_multiplier_bps,
- )?;
+ node_core.set_pow_mining_enabled(ui_config.pow_mining_enabled);
let node: SharedNode = Arc::new(Mutex::new(node_core));
let ui_config = Arc::new(Mutex::new(ui_config));
let mut peers = ui_config.lock().await.peers.clone();
diff --git a/tests/iuna.rs b/tests/iuna.rs
@@ -10,10 +10,9 @@ use iuna::{
PeerDirection, TRANSACTION_BATCH_LIMIT,
},
domain::{
- Amount, BLOCK_REWARD, DEFAULT_FEE_PER_BYTE, DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS,
- FinalizerMode, GenesisBurn, Ledger, MAX_BLOCK_BYTES, MICRO_IUNA, MIN_MINE_REQUIRED_BURN,
- RECOVERY_BLOCK_DELAY_MS, TransactionSubmitOutcome, VDF_TARGET_BLOCK_MS, Wallet, run_vdf,
- verify_vdf,
+ Amount, BLOCK_REWARD, DEFAULT_FEE_PER_BYTE, FinalizerMode, GenesisBurn, Ledger,
+ MAX_BLOCK_BYTES, MICRO_IUNA, MINE_REWARD, RECOVERY_BLOCK_DELAY_MS,
+ TransactionSubmitOutcome, VDF_TARGET_BLOCK_MS, Wallet, run_vdf, verify_vdf,
},
};
use tempfile::tempdir;
@@ -307,7 +306,7 @@ fn block_with_forged_transaction_is_rejected() {
}
#[test]
-fn mine_action_uses_required_burn_reward_and_finalizer_fee() {
+fn mine_action_uses_fixed_reward_and_finalizer_fee() {
let alice = Wallet::from_seed("alice");
let mut allocations = BTreeMap::new();
allocations.insert(alice.address().to_string(), 2 * MICRO_IUNA);
@@ -315,7 +314,7 @@ fn mine_action_uses_required_burn_reward_and_finalizer_fee() {
let mut ledger = Ledger::new(allocations, 10);
submit_burn(&mut ledger, &alice, MICRO_IUNA);
let mine = ledger.build_mine(alice.address()).unwrap();
- assert_eq!(mine.amount(), MIN_MINE_REQUIRED_BURN);
+ assert_eq!(mine.amount(), MINE_REWARD);
assert_eq!(mine.fee(), MICRO_IUNA);
ledger.submit_transaction(mine.clone()).unwrap();
let block = ledger.mine_next_block(&alice, 1).unwrap();
@@ -324,12 +323,12 @@ fn mine_action_uses_required_burn_reward_and_finalizer_fee() {
ledger.apply_block(block).unwrap();
assert_eq!(
ledger.balance_of(alice.address()),
- 2 * MICRO_IUNA + MIN_MINE_REQUIRED_BURN
+ 2 * MICRO_IUNA + MINE_REWARD
);
assert!(!ledger.submit_transaction(mine).unwrap());
assert_eq!(
ledger.balance_of(alice.address()),
- 2 * MICRO_IUNA + MIN_MINE_REQUIRED_BURN
+ 2 * MICRO_IUNA + MINE_REWARD
);
}
@@ -342,7 +341,7 @@ fn mine_action_protocol_fee_is_paid_to_block_finalizer() {
let mut ledger = Ledger::new(allocations, 10);
let mine = ledger.build_mine(alice.address()).unwrap();
- assert_eq!(mine.amount(), MIN_MINE_REQUIRED_BURN);
+ assert_eq!(mine.amount(), MINE_REWARD);
assert_eq!(mine.fee(), MICRO_IUNA);
ledger.submit_transaction(mine).unwrap();
submit_burn(&mut ledger, &bob, MICRO_IUNA);
@@ -351,7 +350,7 @@ fn mine_action_protocol_fee_is_paid_to_block_finalizer() {
assert_eq!(block.reward, MICRO_IUNA);
ledger.apply_block(block).unwrap();
- assert_eq!(ledger.balance_of(alice.address()), MIN_MINE_REQUIRED_BURN);
+ assert_eq!(ledger.balance_of(alice.address()), MINE_REWARD);
assert_eq!(ledger.balance_of(bob.address()), 2 * MICRO_IUNA);
}
@@ -827,9 +826,7 @@ fn pow_only_node_gossips_mine_action_to_pob_only_finalizer() {
DEFAULT_BURN_PER_BLOCK,
DEFAULT_FEE_PER_BYTE,
);
- bob_node
- .set_pow_mining_settings(true, DEFAULT_MINE_REQUIRED_BURN_MULTIPLIER_BPS)
- .unwrap();
+ bob_node.set_pow_mining_enabled(true);
let bob_plan = (1..10_000)
.map(|timestamp| bob_node.prepare_automatic_mining(timestamp))
diff --git a/tests/properties.rs b/tests/properties.rs
@@ -3,8 +3,9 @@ use std::collections::{BTreeMap, BTreeSet};
use iuna::{
app::{InMemoryNetwork, NodeCore},
domain::{
- Amount, ChainSnapshot, GenesisBurn, Ledger, MICRO_IUNA, MINE_FINALIZER_FEE, OutPoint,
- Transaction, TxInput, TxOutput, VDF_TARGET_BLOCK_MS, Wallet, hex_hash, verify_vdf,
+ Amount, ChainSnapshot, GenesisBurn, Ledger, MICRO_IUNA, MINE_FINALIZER_FEE, MINE_REWARD,
+ OutPoint, Transaction, TxInput, TxOutput, VDF_TARGET_BLOCK_MS, Wallet, hex_hash,
+ verify_vdf,
},
};
@@ -166,12 +167,9 @@ fn expected_confirmed_supply(snapshot: &ChainSnapshot) -> Amount {
supply = supply.checked_sub(*amount).expect("burn is funded");
supply = supply.checked_sub(*fee).expect("burn fee is funded");
}
- Transaction::Mine {
- required_burn_amount,
- ..
- } => {
+ Transaction::Mine { .. } => {
supply = supply
- .checked_add(*required_burn_amount)
+ .checked_add(MINE_REWARD)
.expect("mine output does not overflow supply");
}
Transaction::BurnClaim { .. } => {}
@@ -264,15 +262,10 @@ fn apply_reference_transaction(
transaction: &Transaction,
utxos: &mut BTreeMap<OutPoint, TxOutput>,
) {
- if let Transaction::Mine {
- recipient,
- required_burn_amount,
- ..
- } = transaction
- {
+ if let Transaction::Mine { recipient, .. } = transaction {
let output = TxOutput {
address: recipient.clone(),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
};
assert_eq!(transaction.fee(), MINE_FINALIZER_FEE);
insert_reference_outputs(transaction, &[output], utxos);
@@ -345,13 +338,9 @@ fn reference_outputs(transaction: &Transaction) -> Vec<TxOutput> {
match transaction {
Transaction::Transfer { outputs, .. } => outputs.clone(),
Transaction::Burn { change, .. } => change.clone(),
- Transaction::Mine {
- recipient,
- required_burn_amount,
- ..
- } => vec![TxOutput {
+ Transaction::Mine { recipient, .. } => vec![TxOutput {
address: recipient.clone(),
- amount: *required_burn_amount,
+ amount: MINE_REWARD,
}],
Transaction::BurnClaim { .. } => Vec::new(),
}
diff --git a/www/assets/iuna-ui.js b/www/assets/iuna-ui.js
@@ -65,9 +65,6 @@ window.iunaApp = function iunaApp() {
burnFeeDraft: "0.0001",
miningEnabled: false,
powMiningEnabled: false,
- powRequiredBurnMultiplier: 0.8,
- powRequiredBurnMultiplierDraft: "0.8",
- powRequiredBurnMultiplierDirty: false,
burnAmountDirty: false,
transferTo: "",
transferAmount: null,
@@ -545,15 +542,10 @@ window.iunaApp = function iunaApp() {
this.burnFee = status.mining?.automatic_burn_fee ?? this.burnFee;
this.miningEnabled = status.mining?.automatic ?? this.miningEnabled;
this.powMiningEnabled = status.mining?.pow_mining_enabled ?? this.powMiningEnabled;
- this.powRequiredBurnMultiplier =
- (status.mining?.mine_required_burn_multiplier_bps ?? Math.round(this.powRequiredBurnMultiplier * 10000)) / 10000;
if (!this.burnAmountDirty) {
this.burnAmountDraft = this.amountLabel(this.burnAmount);
this.burnFeeDraft = this.amountLabel(this.burnFee);
}
- if (!this.powRequiredBurnMultiplierDirty) {
- this.powRequiredBurnMultiplierDraft = this.powRequiredBurnMultiplier.toString();
- }
this.lastUpdated = new Date();
this.scheduleFeeEstimates();
} catch (error) {
@@ -944,9 +936,7 @@ window.iunaApp = function iunaApp() {
},
async refreshMineFeeEstimate() {
- this.feeEstimates.mine = await this.fetchFeeEstimate("/api/fee-estimate/mine", {
- enabled: this.powMiningEnabled,
- });
+ this.feeEstimates.mine = await this.fetchFeeEstimate("/api/fee-estimate/mine", {});
},
async refreshTransferFeeEstimate() {
@@ -1040,41 +1030,19 @@ window.iunaApp = function iunaApp() {
async setPowMiningEnabled(enabled) {
const previous = this.powMiningEnabled;
- const multiplier = this.powRequiredBurnMultiplierValue();
try {
this.powMiningEnabled = enabled;
await this.postForm(
"/api/settings/pow-mining",
- { enabled, multiplier_bps: Math.round(multiplier * 10000) },
+ { enabled },
enabled ? "PoW mining turned on" : "PoW mining turned off"
);
- this.powRequiredBurnMultiplier = multiplier;
- this.powRequiredBurnMultiplierDraft = multiplier.toString();
- this.powRequiredBurnMultiplierDirty = false;
} catch (error) {
this.powMiningEnabled = previous;
this.showFlash(error.message, "error");
}
},
- async savePowMining() {
- const multiplier = this.powRequiredBurnMultiplierValue();
- try {
- await this.postForm(
- "/api/settings/pow-mining",
- { enabled: this.powMiningEnabled, multiplier_bps: Math.round(multiplier * 10000) },
- this.powMiningEnabled
- ? "PoW mining settings saved"
- : `Mine settings saved while off`
- );
- this.powRequiredBurnMultiplier = multiplier;
- this.powRequiredBurnMultiplierDraft = multiplier.toString();
- this.powRequiredBurnMultiplierDirty = false;
- } catch (error) {
- this.showFlash(error.message, "error");
- }
- },
-
async setKeepTrackOfMetrics(enabled) {
const previous = this.keepTrackOfMetrics;
try {
@@ -1133,64 +1101,8 @@ window.iunaApp = function iunaApp() {
return this.parseiunaAmount(this.burnFeeDraft);
},
- powRequiredBurnMultiplierValue() {
- const value = Number(this.powRequiredBurnMultiplierDraft);
- if (!Number.isFinite(value)) return this.powRequiredBurnMultiplier;
- return Math.min(1, Math.max(0.1, value));
- },
-
- powRequiredBurnMultiplierBps() {
- return Math.round(this.powRequiredBurnMultiplierValue() * 10000);
- },
-
- powMineRewardLimit() {
- return Math.max(100000, Math.trunc(Number(this.status.chain?.mine_reward ?? 1000000)));
- },
-
- powMineRecentBurnTotals() {
- return this.blocks
- .filter((block) => block.height > 0)
- .slice(0, 10)
- .map((block) => this.blockBurnAmount(block));
- },
-
- powMineRecentBurnMin() {
- const totals = this.powMineRecentBurnTotals();
- if (totals.length === 0) return null;
- return Math.min(...totals);
- },
-
- powMineRequiredBurn() {
- const current = Math.max(0, Math.trunc(Number(this.status.mining?.automatic_pow_required_burn_amount ?? 0)));
- if (!this.powRequiredBurnMultiplierDirty) return current;
- const minimum = 100000;
- const maximum = this.powMineRewardLimit();
- const recentMin = this.powMineRecentBurnMin();
- const base = recentMin === null ? maximum : recentMin;
- return Math.min(maximum, Math.max(minimum, Math.round(base * this.powRequiredBurnMultiplierValue())));
- },
-
- powMineNetReward() {
- return this.powMineRequiredBurn();
- },
-
- powMineRecentBurnMax() {
- const totals = this.powMineRecentBurnTotals();
- if (totals.length === 0) return null;
- return Math.max(...totals);
- },
-
- powMineIncludeStatus() {
- const required = this.powMineRequiredBurn();
- const recentMax = this.powMineRecentBurnMax();
- if (recentMax === null) {
- return { kind: "muted", label: "Waiting for burn history", recent: "" };
- }
- const recent = `Recent high: IUNA ${this.amountLabel(recentMax)}`;
- if (recentMax >= required) {
- return { kind: "ready", label: "Recent blocks can include this", recent };
- }
- return { kind: "waiting", label: "May wait for bigger burn blocks", recent };
+ powMineReward() {
+ return Math.max(0, Math.trunc(Number(this.status.chain?.mine_reward ?? 1000000)));
},
autoPowStatusLabel() {