Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 54 additions & 4 deletions crates/chain/tests/api/tx_commitments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use irys_chain::IrysNodeCtx;
use irys_domain::{CommitmentSnapshotStatus, EpochSnapshot};
use irys_testing_utils::initialize_tracing;
use irys_types::{
irys::IrysSigner, Address, CommitmentTransaction, CommitmentTransactionV1, CommitmentType,
NodeConfig, H256, U256,
irys::IrysSigner, Address, CommitmentTransaction, CommitmentType, DataLedger, NodeConfig, H256,
U256,
};
use std::sync::Arc;
use tokio::time::Duration;
Expand Down Expand Up @@ -250,15 +250,65 @@ async fn heavy_test_commitments_3epochs_test() -> eyre::Result<()> {
&signer2_address,
));

// ===== PART 2: Force Submit ledger expansion via additional data =====
// Post additional data that exceeds one full partition to trigger a new Submit ledger slot assignment
let extra_num_chunks = config.consensus.get_mut().num_chunks_in_partition + 2;
let extra_chunk_size = config.consensus.get_mut().chunk_size;

let mut extra_data = Vec::with_capacity((extra_chunk_size * extra_num_chunks) as usize);
for chunk_index in 0..extra_num_chunks {
let chunk_data = vec![chunk_index as u8; extra_chunk_size as usize];
extra_data.extend(chunk_data);
}

// DATA TX (Part 2): Create and post another data transaction
let mut extra_tx = signer1
.create_transaction(extra_data, Some(genesis_block.block_hash))
.expect("To make an additional data transaction");

// Use realistic fee values (these are consistent with pricing helpers used elsewhere in tests)
extra_tx.header.perm_fee = Some(U256::from(4_000_000_000_000_u64));
extra_tx.header.term_fee = U256::from(1_000_000_000_u32);

// Sign and submit the data transaction
let extra_tx = signer1
.sign_transaction(extra_tx)
.expect("extra data tx should be signable");

node.post_data_tx_raw(&extra_tx.header).await;

let res = node.wait_for_mempool(extra_tx.header.id, 5).await;
assert_matches!(res, Ok(()));

// Mine enough blocks to reach the next epoch boundary and apply assignments
info!("MINE THIRD EPOCH BLOCK (Submit expansion):");
node.mine_blocks(num_blocks_in_epoch + 2).await?;

// wait for the block to be migrated
node.wait_until_height_confirmed(10, 50).await?;

// Validate that Submit ledger has at least one partition assigned to slot_index 1
let epoch_snapshot = block_tree_guard.read().canonical_epoch_snapshot();
let submit_assignments: Vec<_> = epoch_snapshot
.partition_assignments
.data_partitions
.values()
.filter(|pa| pa.ledger_id == Some(DataLedger::Submit as u32))
.copied()
.collect();
assert!(
submit_assignments.iter().any(|pa| pa.slot_index == Some(1)),
"Expected a Submit ledger partition assigned to slot_index 1 after exceeding one partition"
);

// Capture storage module infos after Part 2 expansion
sm_infos_before = node
.node_ctx
.block_tree_guard
.read()
.canonical_epoch_snapshot()
.map_storage_modules_to_partition_assignments();

node.wait_until_height_confirmed(6, 10).await?;

node
};

Expand Down
80 changes: 76 additions & 4 deletions crates/types/src/irys.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::storage_pricing::TERM_FEE;

Check failure on line 1 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

unresolved import `crate::storage_pricing::TERM_FEE`

Check failure on line 1 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

unresolved import `crate::storage_pricing::TERM_FEE`

Check failure on line 1 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

unresolved import `crate::storage_pricing::TERM_FEE`

Check failure on line 1 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo doc

unresolved import `crate::storage_pricing::TERM_FEE`
use crate::{
generate_data_root, generate_leaves, resolve_proofs, versioning::Signable as _, Address,
Base64, CommitmentTransaction, DataLedger, DataTransaction, DataTransactionHeader,
Expand Down Expand Up @@ -46,10 +47,32 @@
) -> Result<DataTransaction> {
let mut transaction = self.merklize(data, self.chunk_size as usize, store_data)?;

// TODO: These should be calculated from some pricing params passed in
// as a parameter
transaction.header.perm_fee = Some(U256::from(1));
transaction.header.term_fee = U256::from(1);
// Compute realistic fees using config defaults and pricing helpers
// Term fee: placeholder constant used across pricing until full dynamic pricing is wired
let term_fee = TERM_FEE;

// Use consensus defaults and genesis price to approximate perm fee (suitable for tests)
let config = crate::ConsensusConfig::testing();
let bytes_to_store = U256::from(transaction.header.data_size);

// Calculate base network fee for permanent storage
let cost_per_gb_per_year = config
.annual_cost_per_gb
.cost_per_replica(config.safe_minimum_number_of_years, config.decay_rate)?

Check failure on line 61 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

no method named `cost_per_replica` found for struct `storage_pricing::Amount<(CostPerGb, phantoms::Usd)>` in the current scope

Check failure on line 61 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

no method named `cost_per_replica` found for struct `Amount<(CostPerGb, phantoms::Usd)>` in the current scope

Check failure on line 61 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

no method named `cost_per_replica` found for struct `storage_pricing::Amount<(CostPerGb, phantoms::Usd)>` in the current scope

Check failure on line 61 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

no method named `cost_per_replica` found for struct `Amount<(CostPerGb, phantoms::Usd)>` in the current scope

Check failure on line 61 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

no method named `cost_per_replica` found for struct `Amount<(CostPerGb, Usd)>` in the current scope

Check failure on line 61 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo doc

no method named `cost_per_replica` found for struct `Amount<(CostPerGb, phantoms::Usd)>` in the current scope
.replica_count(config.number_of_ingress_proofs)?;

Check failure on line 62 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`

Check failure on line 62 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`

Check failure on line 62 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`

Check failure on line 62 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo doc

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`
let base_network_fee =
cost_per_gb_per_year.base_network_fee(bytes_to_store, config.genesis_price)?;

Check failure on line 64 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

no field `genesis_price` on type `config::consensus::ConsensusConfig`

Check failure on line 64 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

no field `genesis_price` on type `config::consensus::ConsensusConfig`

Check failure on line 64 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

no field `genesis_price` on type `config::consensus::ConsensusConfig`

Check failure on line 64 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo doc

no field `genesis_price` on type `config::consensus::ConsensusConfig`

// Add ingress proof rewards to get total perm_fee
let perm_fee = base_network_fee.add_ingress_proof_rewards(
term_fee,
config.number_of_ingress_proofs,

Check failure on line 69 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`

Check failure on line 69 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`

Check failure on line 69 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`

Check failure on line 69 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo doc

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`
config.immediate_tx_inclusion_reward_percent,
)?;

// Set computed fees on the header
transaction.header.term_fee = term_fee;
transaction.header.perm_fee = Some(perm_fee.amount);

transaction.header.anchor = anchor;

Expand Down Expand Up @@ -308,4 +331,53 @@

assert_eq!(signer, tx.header.signer);
}

#[test]
fn create_transaction_sets_realistic_fees() {
let config = crate::ConsensusConfig::testing();
let irys = IrysSigner::random_signer(&config);
let data_bytes = vec![1_u8; 1234];

let tx = irys.create_transaction(data_bytes, None).unwrap();

Check failure on line 341 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

mismatched types

Check failure on line 341 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

mismatched types

Check failure on line 341 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

mismatched types

// Term fee should equal the constant TERM_FEE used by pricing helpers
assert_eq!(tx.header.term_fee, crate::storage_pricing::TERM_FEE);

Check failure on line 344 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

cannot find value `TERM_FEE` in module `crate::storage_pricing`

Check failure on line 344 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

cannot find value `TERM_FEE` in module `crate::storage_pricing`

Check failure on line 344 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

cannot find value `TERM_FEE` in module `crate::storage_pricing`

// Perm fee should equal base_network_fee + ingress proof rewards
let bytes_to_store = crate::U256::from(tx.header.data_size);
let cost_per_gb_per_year = config
.annual_cost_per_gb
.cost_per_replica(config.safe_minimum_number_of_years, config.decay_rate)

Check failure on line 350 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

no method named `cost_per_replica` found for struct `storage_pricing::Amount<(CostPerGb, phantoms::Usd)>` in the current scope

Check failure on line 350 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

no method named `cost_per_replica` found for struct `storage_pricing::Amount<(CostPerGb, phantoms::Usd)>` in the current scope

Check failure on line 350 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

no method named `cost_per_replica` found for struct `Amount<(CostPerGb, Usd)>` in the current scope
.unwrap()
.replica_count(config.number_of_ingress_proofs)

Check failure on line 352 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo check

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`

Check failure on line 352 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo test

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`

Check failure on line 352 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

no field `number_of_ingress_proofs` on type `config::consensus::ConsensusConfig`
.unwrap();
let base_network_fee = cost_per_gb_per_year
.base_network_fee(bytes_to_store, config.genesis_price)

Check failure on line 355 in crates/types/src/irys.rs

View workflow job for this annotation

GitHub Actions / cargo clippy

no field `genesis_price` on type `config::consensus::ConsensusConfig`
.unwrap();
let expected_perm = base_network_fee
.add_ingress_proof_rewards(
tx.header.term_fee,
config.number_of_ingress_proofs,
config.immediate_tx_inclusion_reward_percent,
)
.unwrap()
.amount;

assert_eq!(tx.header.perm_fee, Some(expected_perm));
}

#[test]
fn publish_fee_charges_accepts_computed_perm_fee() {
let config = crate::ConsensusConfig::testing();
let irys = IrysSigner::random_signer(&config);
let data = vec![7_u8; 1024];

let tx = irys.create_transaction(data, None).unwrap();
let perm = tx.header.perm_fee.expect("perm_fee set");
let term = tx.header.term_fee;

// Validate perm_fee against distribution logic
crate::transaction::fee_distribution::PublishFeeCharges::new(perm, term, &config)
.expect("perm_fee should be sufficient for ingress rewards + base cost");
}
}
Loading