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:
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");