From 4a47278637f09ff4c0d79de2bde066c03c6a69a0 Mon Sep 17 00:00:00 2001 From: segfault-magnet Date: Fri, 10 Jan 2025 10:31:00 +0100 Subject: [PATCH 1/8] reproduce issue in test --- packages/adapters/storage/src/lib.rs | 127 +++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) diff --git a/packages/adapters/storage/src/lib.rs b/packages/adapters/storage/src/lib.rs index e523e82d..5814532b 100644 --- a/packages/adapters/storage/src/lib.rs +++ b/packages/adapters/storage/src/lib.rs @@ -1207,4 +1207,131 @@ mod tests { Ok(()) } + + #[tokio::test] + async fn test_fee_not_split_across_multiple_bundles() { + use services::block_bundler::port::Storage as BundlerStorage; + use services::cost_reporter::port::Storage as CostStorage; + use services::state_committer::port::Storage as CommiterStorage; + use services::state_listener::port::Storage as ListenerStorage; + use services::types::{CollectNonEmpty, L1Tx, TransactionCostUpdate, TransactionState}; + + // 1) Set up a fresh DB + let storage = start_db().await; + + // 2) Insert BUNDLE A with 1 fragment + let bundle_a_id = storage.next_bundle_id().await.unwrap(); + let fragment_a = Fragment { + data: nonempty![0xaa], + unused_bytes: 0, + total_bytes: 10.try_into().unwrap(), + }; + storage + .insert_bundle_and_fragments( + bundle_a_id, + 1..=5, // Some arbitrary range + nonempty!(fragment_a.clone()), + ) + .await + .unwrap(); + // Grab the fragment ID from BUNDLE A + let fragment_a_id = storage + .oldest_nonfinalized_fragments(0, 10) + .await + .unwrap() + .into_iter() + .find(|bf| bf.fragment.data == fragment_a.data) + .expect("Should have inserted fragment into BUNDLE A") + .id; + + // 3) Insert BUNDLE B with 1 fragment + let bundle_b_id = storage.next_bundle_id().await.unwrap(); + let fragment_b = Fragment { + data: nonempty![0xbb], + unused_bytes: 0, + total_bytes: 20.try_into().unwrap(), + }; + storage + .insert_bundle_and_fragments( + bundle_b_id, + 6..=10, // Another arbitrary range + nonempty!(fragment_b.clone()), + ) + .await + .unwrap(); + // Grab the fragment ID from BUNDLE B + let fragment_b_id = storage + .oldest_nonfinalized_fragments(0, 10) + .await + .unwrap() + .into_iter() + .find(|bf| bf.fragment.data == fragment_b.data) + .expect("Should have inserted fragment into BUNDLE B") + .id; + + // 4) Create a SINGLE transaction referencing BOTH fragments from different bundles + let tx_hash = rand::random::<[u8; 32]>(); + let tx = L1Tx { + hash: tx_hash, + nonce: 999, + ..Default::default() + }; + + storage + .record_pending_tx( + tx.clone(), + nonempty![fragment_a_id, fragment_b_id], + Utc::now(), + ) + .await + .unwrap(); + + // 5) Finalize the transaction with some total fee + let total_fee = 1000u128; // The entire fee we want to distribute + let da_block_height = 9999u64; + let changes = vec![(tx.hash, tx.nonce, TransactionState::Finalized(Utc::now()))]; + let cost_update = TransactionCostUpdate { + tx_hash, + total_fee, + da_block_height, + }; + storage + .update_tx_states_and_costs(vec![], changes, vec![cost_update.clone()]) + .await + .unwrap(); + + // 6) Now query the costs of each final bundle + let all_costs = storage.get_finalized_costs(0, 10).await.unwrap(); + + // We expect to see TWO final bundles in the DB. + // However, the "buggy" logic will incorrectly give the entire fee to only one of them. + let cost_a = all_costs + .iter() + .find(|bc| bc.id == bundle_a_id.get() as u64); + let cost_b = all_costs + .iter() + .find(|bc| bc.id == bundle_b_id.get() as u64); + + // For demonstration, the current (incorrect) logic often sets cost to 1000 for one, + // and 0 (or absent) for the other. Let's assert that the second is missing or 0. + // This test is meant to *expose* that bug: + assert!(cost_a.is_some(), "Should have cost info for first bundles"); + assert!(cost_b.is_some(), "Should have cost info for second bundles"); + + let cost_a = cost_a.unwrap().cost; + let cost_b = cost_b.unwrap().cost; + + // This will fail (or show a mismatch) if the entire 1000 was assigned to only one bundle. + // Realistically, you'd want some proportion, e.g. 10 bytes vs 20 bytes usage => split 1/3 vs 2/3 or similar. + // But let's just show that the second bundle got 0 or is missing: + println!("Debug: costA={cost_a}, costB={cost_b}"); + assert!( + cost_a == 1000 && cost_b == 0, + "BUG: The entire fee should not be assigned to only one bundle.\ + The test reveals that cost_b got no portion of the fee!" + ); + + // If the above assertion passes, it means the bug is *still* present in your code. + // If you fix the bug properly, the test should fail because costB is no longer zero. + } } From 339d08a55c1c83c9060a6f22c5d23d483ea9d42f Mon Sep 17 00:00:00 2001 From: segfault-magnet Date: Fri, 10 Jan 2025 10:44:09 +0100 Subject: [PATCH 2/8] fix bug, update sqlx cache, --- ...4aa35ac1d5ae9763f9383506cd05b42bb0213.json | 40 +++++++++ ...ad735e226634f70e12df55a43df5c10b1b4da.json | 34 ------- packages/adapters/storage/src/lib.rs | 7 +- packages/adapters/storage/src/postgres.rs | 89 ++++++++++++------- 4 files changed, 101 insertions(+), 69 deletions(-) create mode 100644 .sqlx/query-14a630268f676e961c35d4804724aa35ac1d5ae9763f9383506cd05b42bb0213.json delete mode 100644 .sqlx/query-417e5df74ff8190faec540e78ecad735e226634f70e12df55a43df5c10b1b4da.json diff --git a/.sqlx/query-14a630268f676e961c35d4804724aa35ac1d5ae9763f9383506cd05b42bb0213.json b/.sqlx/query-14a630268f676e961c35d4804724aa35ac1d5ae9763f9383506cd05b42bb0213.json new file mode 100644 index 00000000..79c91f94 --- /dev/null +++ b/.sqlx/query-14a630268f676e961c35d4804724aa35ac1d5ae9763f9383506cd05b42bb0213.json @@ -0,0 +1,40 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT\n f.bundle_id,\n SUM(f.total_bytes)::BIGINT AS total_bytes,\n SUM(f.unused_bytes)::BIGINT AS unused_bytes,\n COUNT(*)::BIGINT AS fragment_count\n FROM l1_blob_transaction t\n JOIN l1_transaction_fragments tf ON t.id = tf.transaction_id\n JOIN l1_fragments f ON tf.fragment_id = f.id\n WHERE t.hash = $1\n GROUP BY f.bundle_id\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "bundle_id", + "type_info": "Int4" + }, + { + "ordinal": 1, + "name": "total_bytes", + "type_info": "Int8" + }, + { + "ordinal": 2, + "name": "unused_bytes", + "type_info": "Int8" + }, + { + "ordinal": 3, + "name": "fragment_count", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Bytea" + ] + }, + "nullable": [ + false, + null, + null, + null + ] + }, + "hash": "14a630268f676e961c35d4804724aa35ac1d5ae9763f9383506cd05b42bb0213" +} diff --git a/.sqlx/query-417e5df74ff8190faec540e78ecad735e226634f70e12df55a43df5c10b1b4da.json b/.sqlx/query-417e5df74ff8190faec540e78ecad735e226634f70e12df55a43df5c10b1b4da.json deleted file mode 100644 index 20e6491f..00000000 --- a/.sqlx/query-417e5df74ff8190faec540e78ecad735e226634f70e12df55a43df5c10b1b4da.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT\n f.bundle_id,\n SUM(f.total_bytes)::BIGINT AS total_bytes,\n SUM(f.unused_bytes)::BIGINT AS unused_bytes\n FROM\n l1_blob_transaction t\n JOIN l1_transaction_fragments tf ON t.id = tf.transaction_id\n JOIN l1_fragments f ON tf.fragment_id = f.id\n WHERE\n t.hash = $1\n GROUP BY\n f.bundle_id\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "bundle_id", - "type_info": "Int4" - }, - { - "ordinal": 1, - "name": "total_bytes", - "type_info": "Int8" - }, - { - "ordinal": 2, - "name": "unused_bytes", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Bytea" - ] - }, - "nullable": [ - false, - null, - null - ] - }, - "hash": "417e5df74ff8190faec540e78ecad735e226634f70e12df55a43df5c10b1b4da" -} diff --git a/packages/adapters/storage/src/lib.rs b/packages/adapters/storage/src/lib.rs index 5814532b..2c864385 100644 --- a/packages/adapters/storage/src/lib.rs +++ b/packages/adapters/storage/src/lib.rs @@ -1325,11 +1325,8 @@ mod tests { // Realistically, you'd want some proportion, e.g. 10 bytes vs 20 bytes usage => split 1/3 vs 2/3 or similar. // But let's just show that the second bundle got 0 or is missing: println!("Debug: costA={cost_a}, costB={cost_b}"); - assert!( - cost_a == 1000 && cost_b == 0, - "BUG: The entire fee should not be assigned to only one bundle.\ - The test reveals that cost_b got no portion of the fee!" - ); + assert_eq!(cost_a, 500); + assert_eq!(cost_b, 500); // If the above assertion passes, it means the bug is *still* present in your code. // If you fix the bug properly, the test should fail because costB is no longer zero. diff --git a/packages/adapters/storage/src/postgres.rs b/packages/adapters/storage/src/postgres.rs index bef23139..edb2d01e 100644 --- a/packages/adapters/storage/src/postgres.rs +++ b/packages/adapters/storage/src/postgres.rs @@ -758,41 +758,70 @@ impl Postgres { da_block_height, } in cost_per_tx { - let row = sqlx::query!( + // 1) Fetch the number of fragments and total byte usage per bundle + let rows = sqlx::query!( r#" - SELECT - f.bundle_id, - SUM(f.total_bytes)::BIGINT AS total_bytes, - SUM(f.unused_bytes)::BIGINT AS unused_bytes - FROM - l1_blob_transaction t - JOIN l1_transaction_fragments tf ON t.id = tf.transaction_id - JOIN l1_fragments f ON tf.fragment_id = f.id - WHERE - t.hash = $1 - GROUP BY - f.bundle_id - "#, + SELECT + f.bundle_id, + SUM(f.total_bytes)::BIGINT AS total_bytes, + SUM(f.unused_bytes)::BIGINT AS unused_bytes, + COUNT(*)::BIGINT AS fragment_count + FROM l1_blob_transaction t + JOIN l1_transaction_fragments tf ON t.id = tf.transaction_id + JOIN l1_fragments f ON tf.fragment_id = f.id + WHERE t.hash = $1 + GROUP BY f.bundle_id + "#, tx_hash.as_slice() ) - .fetch_one(&mut *tx) + .fetch_all(&mut *tx) .await?; - let bundle_id = row.bundle_id; - let total_bytes: i64 = row.total_bytes.unwrap_or(0); - let unused_bytes: i64 = row.unused_bytes.unwrap_or(0); - let size_contribution = total_bytes.saturating_sub(unused_bytes) as u64; - - let entry = bundle_updates.entry(bundle_id).or_insert(BundleCostUpdate { - cost_contribution: 0, - size_contribution: 0, - latest_da_block_height: 0, - }); - - entry.cost_contribution = entry.cost_contribution.saturating_add(*total_fee); - entry.size_contribution = entry.size_contribution.saturating_add(size_contribution); - // Update with the latest da_block_height - entry.latest_da_block_height = *da_block_height; + // 2) Calculate the total number of fragments in this transaction + let total_fragments_in_tx = rows + .iter() + .map(|r| r.fragment_count.unwrap_or(0) as u64) + .sum::(); + + // 3) Distribute cost among all bundles based on fragment count, + // but still track the size usage. + for row in rows { + let bundle_id = row.bundle_id; + + // 3a) number of fragments in this bundle + let frag_count_in_bundle = row.fragment_count.unwrap_or(0) as u64; + + // 3b) fraction = how many fragments for this bundle vs. total + let fraction = if total_fragments_in_tx == 0 { + 0.0 + } else { + frag_count_in_bundle as f64 / total_fragments_in_tx as f64 + }; + + // 3c) proportion of the total fee to allocate + let cost_contribution = (*total_fee as f64 * fraction).round() as u128; + + // 3d) "used bytes" for size tracking + let total_bytes = row.total_bytes.unwrap_or(0).max(0) as u64; + let unused_bytes = row.unused_bytes.unwrap_or(0).max(0) as u64; + let used_bytes = total_bytes.saturating_sub(unused_bytes); + + // 3e) update the aggregator + let entry = bundle_updates.entry(bundle_id).or_insert(BundleCostUpdate { + cost_contribution: 0, + size_contribution: 0, + latest_da_block_height: 0, + }); + + // add to cost + entry.cost_contribution = entry.cost_contribution.saturating_add(cost_contribution); + + // update size usage, if you still want to accumulate it + entry.size_contribution = entry.size_contribution.saturating_add(used_bytes); + + // track the most recent da block height + entry.latest_da_block_height = entry.latest_da_block_height.max(*da_block_height); + } } Ok(bundle_updates) From f9a6a75ab964d23b01033d08a34a37c1a11dc3d1 Mon Sep 17 00:00:00 2001 From: segfault-magnet Date: Fri, 10 Jan 2025 10:53:17 +0100 Subject: [PATCH 3/8] cleanup test --- packages/adapters/storage/src/lib.rs | 113 +++++++++++++-------------- 1 file changed, 55 insertions(+), 58 deletions(-) diff --git a/packages/adapters/storage/src/lib.rs b/packages/adapters/storage/src/lib.rs index 2c864385..dbbd0d09 100644 --- a/packages/adapters/storage/src/lib.rs +++ b/packages/adapters/storage/src/lib.rs @@ -194,6 +194,11 @@ impl services::state_pruner::port::Storage for Postgres { #[cfg(test)] mod tests { + use services::block_bundler::port::Storage as BundlerStorage; + use services::cost_reporter::port::Storage as CostStorage; + use services::state_committer::port::Storage as CommiterStorage; + use services::state_listener::port::Storage as ListenerStorage; + use services::types::{L1Tx, TransactionCostUpdate, TransactionState}; use std::time::Duration; use clock::TestClock; @@ -1210,16 +1215,8 @@ mod tests { #[tokio::test] async fn test_fee_not_split_across_multiple_bundles() { - use services::block_bundler::port::Storage as BundlerStorage; - use services::cost_reporter::port::Storage as CostStorage; - use services::state_committer::port::Storage as CommiterStorage; - use services::state_listener::port::Storage as ListenerStorage; - use services::types::{CollectNonEmpty, L1Tx, TransactionCostUpdate, TransactionState}; - - // 1) Set up a fresh DB let storage = start_db().await; - // 2) Insert BUNDLE A with 1 fragment let bundle_a_id = storage.next_bundle_id().await.unwrap(); let fragment_a = Fragment { data: nonempty![0xaa], @@ -1227,14 +1224,10 @@ mod tests { total_bytes: 10.try_into().unwrap(), }; storage - .insert_bundle_and_fragments( - bundle_a_id, - 1..=5, // Some arbitrary range - nonempty!(fragment_a.clone()), - ) + .insert_bundle_and_fragments(bundle_a_id, 1..=5, nonempty!(fragment_a.clone())) .await .unwrap(); - // Grab the fragment ID from BUNDLE A + let fragment_a_id = storage .oldest_nonfinalized_fragments(0, 10) .await @@ -1244,67 +1237,72 @@ mod tests { .expect("Should have inserted fragment into BUNDLE A") .id; - // 3) Insert BUNDLE B with 1 fragment let bundle_b_id = storage.next_bundle_id().await.unwrap(); - let fragment_b = Fragment { - data: nonempty![0xbb], - unused_bytes: 0, - total_bytes: 20.try_into().unwrap(), + + let random_frag = || { + let data: [u8; 2] = thread_rng().gen(); + Fragment { + data: nonempty![data[0], data[1]], + unused_bytes: 0, + total_bytes: 20.try_into().unwrap(), + } }; + + let b_fragments = std::iter::repeat_with(random_frag).take(3).collect_vec(); + storage .insert_bundle_and_fragments( bundle_b_id, 6..=10, // Another arbitrary range - nonempty!(fragment_b.clone()), + NonEmpty::from_vec(b_fragments.clone()).unwrap(), ) .await .unwrap(); - // Grab the fragment ID from BUNDLE B - let fragment_b_id = storage - .oldest_nonfinalized_fragments(0, 10) - .await - .unwrap() - .into_iter() - .find(|bf| bf.fragment.data == fragment_b.data) - .expect("Should have inserted fragment into BUNDLE B") - .id; - // 4) Create a SINGLE transaction referencing BOTH fragments from different bundles - let tx_hash = rand::random::<[u8; 32]>(); + let all_b_fragments = storage.oldest_nonfinalized_fragments(0, 10).await.unwrap(); + let find_id = |data: &NonEmpty| { + all_b_fragments + .iter() + .find(|bf| bf.fragment.data == *data) + .expect("Should have inserted fragment B1") + .id + }; + + let fragment_b1_id = find_id(&b_fragments[0].data); + let fragment_b2_id = find_id(&b_fragments[1].data); + let fragment_b3_id = find_id(&b_fragments[2].data); + + let tx_hash = [0; 32]; let tx = L1Tx { hash: tx_hash, - nonce: 999, ..Default::default() }; + let all_frag_ids = nonempty![ + fragment_a_id, + fragment_b1_id, + fragment_b2_id, + fragment_b3_id + ]; storage - .record_pending_tx( - tx.clone(), - nonempty![fragment_a_id, fragment_b_id], - Utc::now(), - ) + .record_pending_tx(tx.clone(), all_frag_ids, Utc::now()) .await .unwrap(); - // 5) Finalize the transaction with some total fee - let total_fee = 1000u128; // The entire fee we want to distribute - let da_block_height = 9999u64; + let total_fee = 1000u128; let changes = vec![(tx.hash, tx.nonce, TransactionState::Finalized(Utc::now()))]; let cost_update = TransactionCostUpdate { tx_hash, total_fee, - da_block_height, + da_block_height: 9999, }; storage .update_tx_states_and_costs(vec![], changes, vec![cost_update.clone()]) .await .unwrap(); - // 6) Now query the costs of each final bundle let all_costs = storage.get_finalized_costs(0, 10).await.unwrap(); - // We expect to see TWO final bundles in the DB. - // However, the "buggy" logic will incorrectly give the entire fee to only one of them. let cost_a = all_costs .iter() .find(|bc| bc.id == bundle_a_id.get() as u64); @@ -1312,23 +1310,22 @@ mod tests { .iter() .find(|bc| bc.id == bundle_b_id.get() as u64); - // For demonstration, the current (incorrect) logic often sets cost to 1000 for one, - // and 0 (or absent) for the other. Let's assert that the second is missing or 0. - // This test is meant to *expose* that bug: - assert!(cost_a.is_some(), "Should have cost info for first bundles"); - assert!(cost_b.is_some(), "Should have cost info for second bundles"); + assert!( + cost_a.is_some(), + "Should have cost info for first bundle (A)" + ); + assert!( + cost_b.is_some(), + "Should have cost info for second bundle (B)" + ); let cost_a = cost_a.unwrap().cost; let cost_b = cost_b.unwrap().cost; - // This will fail (or show a mismatch) if the entire 1000 was assigned to only one bundle. - // Realistically, you'd want some proportion, e.g. 10 bytes vs 20 bytes usage => split 1/3 vs 2/3 or similar. - // But let's just show that the second bundle got 0 or is missing: - println!("Debug: costA={cost_a}, costB={cost_b}"); - assert_eq!(cost_a, 500); - assert_eq!(cost_b, 500); - - // If the above assertion passes, it means the bug is *still* present in your code. - // If you fix the bug properly, the test should fail because costB is no longer zero. + // - A has 1 fragment + // - B has 3 fragments + // => total 4 fragments, so we expect 1/4 of the fee for A (250) and 3/4 (750) for B. + assert_eq!(cost_a, 250, "Bundle A should get 25% of the 1000 fee"); + assert_eq!(cost_b, 750, "Bundle B should get 75% of the 1000 fee"); } } From 242a73d20d2823d66a6ca18bf41be42cec912adc Mon Sep 17 00:00:00 2001 From: segfault-magnet Date: Fri, 10 Jan 2025 11:15:58 +0100 Subject: [PATCH 4/8] cleanup --- packages/adapters/storage/src/postgres.rs | 34 ++++++++--------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/packages/adapters/storage/src/postgres.rs b/packages/adapters/storage/src/postgres.rs index edb2d01e..d29f2c65 100644 --- a/packages/adapters/storage/src/postgres.rs +++ b/packages/adapters/storage/src/postgres.rs @@ -758,7 +758,6 @@ impl Postgres { da_block_height, } in cost_per_tx { - // 1) Fetch the number of fragments and total byte usage per bundle let rows = sqlx::query!( r#" SELECT @@ -777,49 +776,40 @@ impl Postgres { .fetch_all(&mut *tx) .await?; - // 2) Calculate the total number of fragments in this transaction let total_fragments_in_tx = rows .iter() .map(|r| r.fragment_count.unwrap_or(0) as u64) .sum::(); - // 3) Distribute cost among all bundles based on fragment count, - // but still track the size usage. for row in rows { let bundle_id = row.bundle_id; - // 3a) number of fragments in this bundle let frag_count_in_bundle = row.fragment_count.unwrap_or(0) as u64; + let total_bytes = row.total_bytes.unwrap_or(0).max(0) as u64; + let unused_bytes = row.unused_bytes.unwrap_or(0).max(0) as u64; + let used_bytes = total_bytes.saturating_sub(unused_bytes); - // 3b) fraction = how many fragments for this bundle vs. total - let fraction = if total_fragments_in_tx == 0 { - 0.0 + const PPM: u128 = 1_000_000; + let fraction_in_ppm = if total_fragments_in_tx == 0 { + 0u128 } else { - frag_count_in_bundle as f64 / total_fragments_in_tx as f64 + u128::from(frag_count_in_bundle) + .saturating_mul(PPM) + .saturating_div(u128::from(total_fragments_in_tx)) }; - // 3c) proportion of the total fee to allocate - let cost_contribution = (*total_fee as f64 * fraction).round() as u128; + let cost_contribution = fraction_in_ppm + .saturating_mul(*total_fee) + .saturating_div(PPM); - // 3d) "used bytes" for size tracking - let total_bytes = row.total_bytes.unwrap_or(0).max(0) as u64; - let unused_bytes = row.unused_bytes.unwrap_or(0).max(0) as u64; - let used_bytes = total_bytes.saturating_sub(unused_bytes); - - // 3e) update the aggregator let entry = bundle_updates.entry(bundle_id).or_insert(BundleCostUpdate { cost_contribution: 0, size_contribution: 0, latest_da_block_height: 0, }); - // add to cost entry.cost_contribution = entry.cost_contribution.saturating_add(cost_contribution); - - // update size usage, if you still want to accumulate it entry.size_contribution = entry.size_contribution.saturating_add(used_bytes); - - // track the most recent da block height entry.latest_da_block_height = entry.latest_da_block_height.max(*da_block_height); } } From 7e6e035e9bc7083462d57d34411da03186aa3ab0 Mon Sep 17 00:00:00 2001 From: segfault-magnet Date: Fri, 10 Jan 2025 11:17:04 +0100 Subject: [PATCH 5/8] group imports --- packages/adapters/storage/src/lib.rs | 25 +++++++++++-------- packages/adapters/storage/src/postgres.rs | 21 ++++++++-------- .../adapters/storage/src/test_instance.rs | 11 ++++---- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/packages/adapters/storage/src/lib.rs b/packages/adapters/storage/src/lib.rs index dbbd0d09..1866e804 100644 --- a/packages/adapters/storage/src/lib.rs +++ b/packages/adapters/storage/src/lib.rs @@ -194,17 +194,18 @@ impl services::state_pruner::port::Storage for Postgres { #[cfg(test)] mod tests { - use services::block_bundler::port::Storage as BundlerStorage; - use services::cost_reporter::port::Storage as CostStorage; - use services::state_committer::port::Storage as CommiterStorage; - use services::state_listener::port::Storage as ListenerStorage; - use services::types::{L1Tx, TransactionCostUpdate, TransactionState}; use std::time::Duration; use clock::TestClock; use itertools::Itertools; use rand::{thread_rng, Rng}; - use services::types::{nonempty, CollectNonEmpty}; + use services::{ + block_bundler::port::Storage as BundlerStorage, + cost_reporter::port::Storage as CostStorage, + state_committer::port::Storage as CommiterStorage, + state_listener::port::Storage as ListenerStorage, + types::{nonempty, CollectNonEmpty, L1Tx, TransactionCostUpdate, TransactionState}, + }; use super::*; @@ -462,8 +463,9 @@ mod tests { #[tokio::test] async fn can_get_last_time_a_fragment_was_finalized() { - use services::state_committer::port::Storage; - use services::state_listener::port::Storage as ListenerStorage; + use services::{ + state_committer::port::Storage, state_listener::port::Storage as ListenerStorage, + }; // given let storage = start_db().await; @@ -926,9 +928,10 @@ mod tests { #[tokio::test] async fn can_update_costs() -> Result<()> { - use services::cost_reporter::port::Storage; - use services::state_committer::port::Storage as StateStorage; - use services::state_listener::port::Storage as ListenerStorage; + use services::{ + cost_reporter::port::Storage, state_committer::port::Storage as StateStorage, + state_listener::port::Storage as ListenerStorage, + }; // given let storage = start_db().await; diff --git a/packages/adapters/storage/src/postgres.rs b/packages/adapters/storage/src/postgres.rs index d29f2c65..014e599f 100644 --- a/packages/adapters/storage/src/postgres.rs +++ b/packages/adapters/storage/src/postgres.rs @@ -1,6 +1,5 @@ use std::{collections::HashMap, ops::RangeInclusive}; -use crate::postgres::tables::u128_to_bigdecimal; use itertools::Itertools; use metrics::{prometheus::IntGauge, RegistersMetrics}; use services::types::{ @@ -14,7 +13,10 @@ use sqlx::{ }; use super::error::{Error, Result}; -use crate::mappings::tables::{self, L1TxState}; +use crate::{ + mappings::tables::{self, L1TxState}, + postgres::tables::u128_to_bigdecimal, +}; #[derive(Debug, Clone)] struct Metrics { @@ -1188,15 +1190,13 @@ fn create_ranges(heights: Vec) -> Vec> { mod tests { use std::{env, fs, path::Path}; + use rand::Rng; + use services::types::{CollectNonEmpty, Fragment, L1Tx, TransactionState}; use sqlx::{Executor, PgPool, Row}; use tokio::time::Instant; - use crate::test_instance; - use super::*; - - use rand::Rng; - use services::types::{CollectNonEmpty, Fragment, L1Tx, TransactionState}; + use crate::test_instance; #[tokio::test] async fn test_second_migration_applies_successfully() { @@ -1459,9 +1459,10 @@ mod tests { #[tokio::test] async fn stress_test_update_costs() -> Result<()> { - use services::block_bundler::port::Storage; - use services::state_committer::port::Storage as CommitterStorage; - use services::state_listener::port::Storage as ListenerStorage; + use services::{ + block_bundler::port::Storage, state_committer::port::Storage as CommitterStorage, + state_listener::port::Storage as ListenerStorage, + }; let mut rng = rand::thread_rng(); diff --git a/packages/adapters/storage/src/test_instance.rs b/packages/adapters/storage/src/test_instance.rs index 4056593e..6d9d70d7 100644 --- a/packages/adapters/storage/src/test_instance.rs +++ b/packages/adapters/storage/src/test_instance.rs @@ -1,3 +1,9 @@ +use std::{ + borrow::Cow, + ops::RangeInclusive, + sync::{Arc, Weak}, +}; + use delegate::delegate; use services::{ block_bundler, block_committer, block_importer, @@ -8,11 +14,6 @@ use services::{ }, }; use sqlx::Executor; -use std::{ - borrow::Cow, - ops::RangeInclusive, - sync::{Arc, Weak}, -}; use testcontainers::{ core::{ContainerPort, WaitFor}, runners::AsyncRunner, From d614e98c3fb54258ae801fc796856f46fef113bb Mon Sep 17 00:00:00 2001 From: segfault-magnet Date: Fri, 10 Jan 2025 11:22:53 +0100 Subject: [PATCH 6/8] remove imports in fn blocks --- packages/adapters/storage/src/lib.rs | 42 +--------------------------- 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/packages/adapters/storage/src/lib.rs b/packages/adapters/storage/src/lib.rs index 1866e804..54aad11e 100644 --- a/packages/adapters/storage/src/lib.rs +++ b/packages/adapters/storage/src/lib.rs @@ -201,6 +201,7 @@ mod tests { use rand::{thread_rng, Rng}; use services::{ block_bundler::port::Storage as BundlerStorage, + block_importer::port::Storage, cost_reporter::port::Storage as CostStorage, state_committer::port::Storage as CommiterStorage, state_listener::port::Storage as ListenerStorage, @@ -463,10 +464,6 @@ mod tests { #[tokio::test] async fn can_get_last_time_a_fragment_was_finalized() { - use services::{ - state_committer::port::Storage, state_listener::port::Storage as ListenerStorage, - }; - // given let storage = start_db().await; @@ -674,10 +671,6 @@ mod tests { #[tokio::test] async fn excludes_fragments_from_bundles_ending_before_starting_height() { - use services::{ - block_bundler::port::Storage, state_committer::port::Storage as CommitterStorage, - }; - // given let storage = start_db().await; let starting_height = 10; @@ -727,10 +720,6 @@ mod tests { #[tokio::test] async fn includes_fragments_from_bundles_ending_at_starting_height() { - use services::{ - block_bundler::port::Storage, state_committer::port::Storage as CommitterStorage, - }; - // given let storage = start_db().await; let starting_height = 10; @@ -764,10 +753,6 @@ mod tests { #[tokio::test] async fn can_get_next_bundle_id() { - use services::{ - block_bundler::port::Storage, state_committer::port::Storage as CommitterStorage, - }; - // given let storage = start_db().await; let starting_height = 10; @@ -801,8 +786,6 @@ mod tests { #[tokio::test] async fn empty_db_reports_missing_heights() -> Result<()> { - use services::block_importer::port::Storage; - // given let current_height = 10; let storage = start_db().await; @@ -818,8 +801,6 @@ mod tests { #[tokio::test] async fn missing_blocks_no_holes() -> Result<()> { - use services::block_importer::port::Storage; - // given let current_height = 10; let storage = start_db().await; @@ -837,8 +818,6 @@ mod tests { #[tokio::test] async fn reports_holes_in_blocks() -> Result<()> { - use services::block_importer::port::Storage; - // given let current_height = 15; let storage = start_db().await; @@ -857,8 +836,6 @@ mod tests { #[tokio::test] async fn can_retrieve_fragments_submitted_by_tx() -> Result<()> { - use services::state_committer::port::Storage; - // given let storage = start_db().await; @@ -883,8 +860,6 @@ mod tests { #[tokio::test] async fn can_get_latest_pending_txs() -> Result<()> { - use services::state_committer::port::Storage; - // given let storage = start_db().await; @@ -928,11 +903,6 @@ mod tests { #[tokio::test] async fn can_update_costs() -> Result<()> { - use services::{ - cost_reporter::port::Storage, state_committer::port::Storage as StateStorage, - state_listener::port::Storage as ListenerStorage, - }; - // given let storage = start_db().await; @@ -1028,8 +998,6 @@ mod tests { #[tokio::test] async fn costs_returned_only_for_finalized_bundles() { - use services::cost_reporter::port::Storage; - // given let storage = start_db().await; let cost = 1000u128; @@ -1069,8 +1037,6 @@ mod tests { #[tokio::test] async fn costs_returned_only_for_finalized_with_replacement_txs() { - use services::cost_reporter::port::Storage; - // given let storage = start_db().await; let cost = 1000u128; @@ -1108,8 +1074,6 @@ mod tests { #[tokio::test] async fn respects_from_block_height_and_limit_in_get_finalized_costs() -> Result<()> { - use services::cost_reporter::port::Storage; - // given let storage = start_db().await; @@ -1146,8 +1110,6 @@ mod tests { #[tokio::test] async fn get_finalized_costs_from_middle_of_range() -> Result<()> { - use services::cost_reporter::port::Storage; - // given let storage = start_db().await; @@ -1184,8 +1146,6 @@ mod tests { #[tokio::test] async fn get_latest_finalized_costs() -> Result<()> { - use services::cost_reporter::port::Storage; - // given let storage = start_db().await; From f65a6756edd03c95022f4f260426b4d6b75d7ece Mon Sep 17 00:00:00 2001 From: segfault-magnet Date: Fri, 10 Jan 2025 11:35:09 +0100 Subject: [PATCH 7/8] fix typo --- packages/adapters/storage/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapters/storage/src/lib.rs b/packages/adapters/storage/src/lib.rs index 54aad11e..45267e26 100644 --- a/packages/adapters/storage/src/lib.rs +++ b/packages/adapters/storage/src/lib.rs @@ -203,7 +203,7 @@ mod tests { block_bundler::port::Storage as BundlerStorage, block_importer::port::Storage, cost_reporter::port::Storage as CostStorage, - state_committer::port::Storage as CommiterStorage, + state_committer::port::Storage as CommitterStorage, state_listener::port::Storage as ListenerStorage, types::{nonempty, CollectNonEmpty, L1Tx, TransactionCostUpdate, TransactionState}, }; From 848c02385936dee552fb0bf243b4a5c243e01e99 Mon Sep 17 00:00:00 2001 From: segfault-magnet Date: Fri, 10 Jan 2025 16:04:00 +0100 Subject: [PATCH 8/8] rename test --- packages/adapters/storage/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapters/storage/src/lib.rs b/packages/adapters/storage/src/lib.rs index 45267e26..a8ec7adb 100644 --- a/packages/adapters/storage/src/lib.rs +++ b/packages/adapters/storage/src/lib.rs @@ -1177,7 +1177,7 @@ mod tests { } #[tokio::test] - async fn test_fee_not_split_across_multiple_bundles() { + async fn test_fee_split_across_multiple_bundles() { let storage = start_db().await; let bundle_a_id = storage.next_bundle_id().await.unwrap();