iuna

iuna - experimental devnet protocol
git clone https://iuna.jhx.app/git/iuna.git
Log | Files | Refs | README | LICENSE

commit 8840d73382f1c8af915bafe3885fb91c44e34719
parent e59bdc98ccecd9a6b46a3bba46b1e1babf3cb000
Author: Joris Hartog <jorishartog@hotmail.com>
Date:   Fri,  7 Aug 2026 15:22:21 +0200

Make automatic burns preserve configured amount

Diffstat:
Msrc/app.rs | 36+++++++++++++++++++++++++++++++++++-
Mtests/iuna.rs | 21+++++++++++++++++++++
2 files changed, 56 insertions(+), 1 deletion(-)

diff --git a/src/app.rs b/src/app.rs @@ -1174,6 +1174,17 @@ impl NodeCore { }) } + fn build_blinded_burn_with_fee_on_ledger( + &self, + ledger: &Ledger, + amount: Amount, + fee: Amount, + ) -> Result<BuiltBlindedTransaction> { + let expires_at_height = self.default_blinded_transaction_expiry_height(); + let tx = ledger.build_burn(self.wallet.unlocked()?, amount, fee)?; + ledger.build_blinded_transaction(self.wallet.unlocked()?, tx, expires_at_height) + } + fn build_transfer_with_fee_rate( &self, to: impl Into<String>, @@ -1582,8 +1593,31 @@ impl NodeCore { fee_per_byte: Amount, balance: Amount, ) -> Option<BuiltBlindedTransaction> { + let target = self.burn_per_block.min(balance); + if target == 0 { + return None; + } + let exact_at_fee_rate = + self.build_blinded_burn_with_fee_rate_on_ledger(ledger, target, fee_per_byte); + if let Ok((built, estimate)) = exact_at_fee_rate { + if target + .checked_add(estimate.fee) + .is_some_and(|required| required <= balance) + { + return Some(built); + } + } + if self.burn_per_block <= balance { + let affordable_fee = balance.saturating_sub(target); + if let Ok(built) = + self.build_blinded_burn_with_fee_on_ledger(ledger, target, affordable_fee) + { + return Some(built); + } + } + let mut low = 1; - let mut high = self.burn_per_block.min(balance); + let mut high = target; let mut best = None; while low <= high { let amount = low + (high - low) / 2; diff --git a/tests/iuna.rs b/tests/iuna.rs @@ -738,6 +738,27 @@ fn automatic_mining_caps_burn_to_spendable_balance_after_fee() { } #[test] +fn automatic_mining_preserves_configured_burn_when_only_fee_is_short() { + let alice = Wallet::from_seed("auto-burn-exact-target-alice"); + let mut allocations = BTreeMap::new(); + allocations.insert(alice.address().to_string(), MICRO_IUNA); + let mut node = NodeCore::new(NodeConfig { + wallet: alice.clone(), + genesis_allocations: allocations, + vdf_rounds: 10, + burn_per_block: MICRO_IUNA, + burn_fee: DEFAULT_FEE_PER_BYTE, + }); + + let outcome = node.automatic_mine_once(1); + + let burned = outcome.burned.as_ref().unwrap(); + assert_eq!(burned.amount(), MICRO_IUNA); + assert_eq!(burned.fee(), 0); + assert!(outcome.block.is_some()); +} + +#[test] fn setting_burn_rate_after_running_at_zero_prepares_private_anchor_burn() { let alice = Wallet::from_seed("alice"); let bob = Wallet::from_seed("bob");