Shard guest: the D4 proving-payment split mirrored behind FixtureEnv::proving_payment_to_pool (known-failed first; the ELF and program id not yet re-pinned)
The guest core applies the node's split at both charge sites (proving_payment_split, the same arithmetic as igneum_exec::executor): off, the whole proving charge burns as every existing fixture recorded; on, 90 percent of pgas used x f_p is credited to PROVING_POOL_ADDRESS and 10 percent burns. The flag is serde-default false, so every fixture written before it reads unchanged and reproduces its roots; the exporter reads it from the node's segment JSON (provingPaymentToPool, proving-payment 930b6322 of the fork). Test: host fee_switch_tests::the_proving_payment_flag_moves_90_percent_of_the_charge_to_the_pool (off: the recorded roots and the subsidy credit alone in the escrow; on: 90 percent of the charges in the escrow, another post-root, the proving work unchanged); fee-switch tests 5 passed on build-2 at 17:44 UK. The guest ELF, verifying key and program id in elf/ are NOT re-pinned by this commit: until pin-guests.sh runs on the new sources and the object pins the new id, proving_payment_activation_daa stays at never on every object. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
1dc7c42ca4
commit
7dd7c35e1a
4 changed files with 68 additions and 4 deletions
|
|
@ -191,6 +191,17 @@ pub struct RangeOutcome {
|
|||
/// Executes a contiguous range of a segment's transactions on `db` from `carry_in` (design 1.2 and 5.1): the
|
||||
/// rewards first when given (the segment's first shard), then every transaction in order. `db` is the state
|
||||
/// before the range on entry and after it on return. With `roots`, the state root is computed at every boundary.
|
||||
/// Igneum 2.0 D4: how a transaction's proving charge divides, exactly as the node (`igneum_exec::executor::proving_payment_split`).
|
||||
/// Off: the whole charge burns. On: 90 percent is the provers' payment (to the pool escrow), 10 percent burns, the
|
||||
/// rounding wei to the burn.
|
||||
pub fn proving_payment_split(charge: u128, to_pool: bool) -> (u128, u128) {
|
||||
if !to_pool {
|
||||
return (0, charge);
|
||||
}
|
||||
let payment = charge / 100 * 90 + (charge % 100) * 90 / 100;
|
||||
(payment, charge - payment)
|
||||
}
|
||||
|
||||
pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, schedule: &FeeSchedule, rewards: Option<(&[(Address, U256)], U256, &[(Address, U256)])>, txs: &[ShardTx], carry_in: Carry, roots: bool) -> RangeOutcome {
|
||||
// The fee set that meters this chain block: the schedule read at the block's own DAA score, so the guest
|
||||
// replays the height switch as the node does. The base fees carried in are raised to this set's floors here
|
||||
|
|
@ -287,10 +298,14 @@ pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, schedul
|
|||
let (status, gas_used, logs) = if insp.over_budget {
|
||||
let gas_used = tx.gas_limit();
|
||||
let burned_exec = (gas_used as u128) * base_fee_exec;
|
||||
let burned_proving = ((pgas_used as u128) * base_fee_proving).min(budget.saturating_sub(burned_exec));
|
||||
let tip_total = budget.saturating_sub(burned_exec + burned_proving);
|
||||
let proving_charge = ((pgas_used as u128) * base_fee_proving).min(budget.saturating_sub(burned_exec));
|
||||
let tip_total = budget.saturating_sub(burned_exec + proving_charge);
|
||||
db.bump_nonce(tx.sender);
|
||||
db.sub_balance(tx.sender, U256::from(budget));
|
||||
let (proving_payment, _burned_proving) = proving_payment_split(proving_charge, env.proving_payment_to_pool);
|
||||
if proving_payment > 0 {
|
||||
db.add_balance(PROVING_POOL_ADDRESS, U256::from(proving_payment));
|
||||
}
|
||||
let shares = developer_shares(tip_total, &insp.attributions, |code| registered_payee(db, code));
|
||||
let dev_total: u128 = shares.iter().map(|(_, w)| *w).sum();
|
||||
db.add_balance(t.miner, U256::from(tip_total - dev_total));
|
||||
|
|
@ -315,8 +330,12 @@ pub fn execute_range(db: &mut IgneumDb, chain_id: u64, env: &FixtureEnv, schedul
|
|||
(status, gas_used, logs)
|
||||
};
|
||||
// The proving charge never takes the sender past the signed budget (design 4.1).
|
||||
let burned_proving = ((pgas_used as u128) * base_fee_proving).min(budget.saturating_sub((gas_used as u128) * price));
|
||||
db.sub_balance(tx.sender, U256::from(burned_proving));
|
||||
let proving_charge = ((pgas_used as u128) * base_fee_proving).min(budget.saturating_sub((gas_used as u128) * price));
|
||||
db.sub_balance(tx.sender, U256::from(proving_charge));
|
||||
let (proving_payment, _burned_proving) = proving_payment_split(proving_charge, env.proving_payment_to_pool);
|
||||
if proving_payment > 0 {
|
||||
db.add_balance(PROVING_POOL_ADDRESS, U256::from(proving_payment));
|
||||
}
|
||||
let tip_total = (gas_used as u128) * (price - base_fee_exec);
|
||||
let shares = developer_shares(tip_total, &insp.attributions, |code| registered_payee(db, code));
|
||||
let dev_total: u128 = shares.iter().map(|(_, w)| *w).sum();
|
||||
|
|
|
|||
|
|
@ -25,6 +25,12 @@ pub struct FixtureEnv {
|
|||
/// A fixture written before the switch existed has none, and 0 keeps it on the schedule's base set.
|
||||
#[serde(default)]
|
||||
pub daa_score: u64,
|
||||
/// Igneum 2.0 D4 (`docs/design/proving-payment.md`): the node's `proving_payment_activation_daa` reached at this
|
||||
/// chain block, so a transaction's proving charge (pgas used x f_p) is the provers' payment: 90 percent credited to
|
||||
/// the proving pool escrow, 10 percent burned; false (every fixture written before the field) burns the whole
|
||||
/// charge, as spec 5.1 stood. Exactly what the node does (`igneum_exec::executor::proving_payment_split`).
|
||||
#[serde(default)]
|
||||
pub proving_payment_to_pool: bool,
|
||||
}
|
||||
|
||||
/// One block of the segment in sequence order: its miner (the beneficiary of its transactions) and its
|
||||
|
|
|
|||
|
|
@ -128,6 +128,8 @@ fn fixture_of(export: &Value, segments: &[Value], n: usize, hashes: &[(u64, B256
|
|||
None if fees.v1_activation_daa == 0 || fees.v1_activation_daa == u64::MAX => 0,
|
||||
None => bail!("segment {}: the dump carries no daaScore and the schedule switches at DAA {}; re-export with tools/prove-fixtures/gen.mjs, which writes it", seg["number"], fees.v1_activation_daa),
|
||||
},
|
||||
// Igneum 2.0 D4: the node says whether this block's proving charges went 90 percent to the pool (absent before the field: no)
|
||||
proving_payment_to_pool: seg["provingPaymentToPool"].as_bool().unwrap_or(false),
|
||||
};
|
||||
let rewards = seg["rewards"].as_array().context("rewards")?.iter().map(|r| Ok((addr(&r["address"])?, u256(&r["wei"])?))).collect::<Result<Vec<_>>>()?;
|
||||
let proving_pool_credit: U256 = seg["provingPoolCredit"].as_str().context("provingPoolCredit")?.parse()?;
|
||||
|
|
|
|||
|
|
@ -980,6 +980,43 @@ mod fee_switch_tests {
|
|||
native_matches(&f);
|
||||
}
|
||||
|
||||
/// Igneum 2.0 D4, known-failed first: with `proving_payment_to_pool` off the fixture reproduces its recorded roots
|
||||
/// and the pool escrow holds only the 20 percent subsidy credit; with it on, 90 percent of the block's proving
|
||||
/// charges (pgas used x f_p over the executed transactions) sit in PROVING_POOL_ADDRESS, the post-root differs from
|
||||
/// the recorded one (another statement, which is why the floor stays at never until this guest is pinned), and the
|
||||
/// split's arithmetic is the node's.
|
||||
#[test]
|
||||
fn the_proving_payment_flag_moves_90_percent_of_the_charge_to_the_pool() {
|
||||
use igneum_prove_core::config::PROVING_POOL_ADDRESS;
|
||||
use igneum_prove_core::executor::{execute_block, load_pre_state, proving_payment_split};
|
||||
let f = load("fees-v1-shards2.json");
|
||||
assert!(f.expected.pgas_used > 0);
|
||||
// off: the recorded roots, the pool holds the subsidy credit alone
|
||||
let mut db = load_pre_state(&f.block);
|
||||
let before = db.balance(PROVING_POOL_ADDRESS);
|
||||
let off = execute_block(&mut db, &f.block);
|
||||
assert_eq!(off.state_root, f.expected.post_state_root);
|
||||
let pool_off = db.balance(PROVING_POOL_ADDRESS) - before;
|
||||
assert_eq!(pool_off, f.block.proving_pool_credit, "off: the 20 percent credit alone reaches the escrow");
|
||||
// on: 90 percent of every executed transaction's proving charge joins it
|
||||
let mut block = f.block.clone();
|
||||
block.env.proving_payment_to_pool = true;
|
||||
let mut db = load_pre_state(&block);
|
||||
let before = db.balance(PROVING_POOL_ADDRESS);
|
||||
let on = execute_block(&mut db, &block);
|
||||
let pool_on = db.balance(PROVING_POOL_ADDRESS) - before;
|
||||
let charges: u128 = on.executed.iter().map(|t| t.pgas_used as u128 * block.env.base_fee_proving as u128).sum();
|
||||
let payment: u128 = on.executed.iter().map(|t| proving_payment_split(t.pgas_used as u128 * block.env.base_fee_proving as u128, true).0).sum();
|
||||
assert!(charges > 0, "the fixture carries proving charges");
|
||||
assert_eq!(pool_on - pool_off, alloy_primitives::U256::from(payment), "90 percent of the charges reach the escrow");
|
||||
assert!(payment >= charges / 100 * 90 && payment <= charges / 100 * 90 + on.executed.len() as u128);
|
||||
assert_ne!(on.state_root, off.state_root, "another post-root: another statement");
|
||||
assert_eq!(on.pgas_used, off.pgas_used, "the proving work is unchanged");
|
||||
assert_eq!(proving_payment_split(100, true), (90, 10));
|
||||
assert_eq!(proving_payment_split(7, true), (6, 1));
|
||||
assert_eq!(proving_payment_split(7, false), (0, 7));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_v1_blocks_at_and_above_the_switch() {
|
||||
for (name, shards) in [("fees-v1-shards2.json", 2usize), ("fees-v1-shards3.json", 3)] {
|
||||
|
|
|
|||
Loading…
Reference in a new issue