Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gas_price_service_v1): define RunnableTask for GasPriceServiceV1 #2416

Merged
merged 16 commits into from
Nov 14, 2024
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- [2386](https://github.com/FuelLabs/fuel-core/pull/2386): Add a flag to define the maximum number of file descriptors that RocksDB can use. By default it's half of the OS limit.
- [2376](https://github.com/FuelLabs/fuel-core/pull/2376): Add a way to fetch transactions in P2P without specifying a peer.
- [2327](https://github.com/FuelLabs/fuel-core/pull/2327): Add more services tests and more checks of the pool. Also add an high level documentation for users of the pool and contributors.
- [2416](https://github.com/FuelLabs/fuel-core/issues/2416): Define the `GasPriceServiceV1` task.


### Fixed
- [2366](https://github.com/FuelLabs/fuel-core/pull/2366): The `importer_gas_price_for_block` metric is properly collected.
Expand Down
2 changes: 1 addition & 1 deletion crates/client/assets/debugAdapterProtocol.json
Original file line number Diff line number Diff line change
Expand Up @@ -1440,7 +1440,7 @@
{ "$ref": "#/definitions/Request" },
{
"type": "object",
"description": "Replaces all existing instruction breakpoints. Typically, instruction breakpoints would be set from a diassembly window. \nTo clear all instruction breakpoints, specify an empty array.\nWhen an instruction breakpoint is hit, a 'stopped' event (with reason 'instruction breakpoint') is generated.\nClients should only call this request if the capability 'supportsInstructionBreakpoints' is true.",
"description": "Replaces all existing instruction breakpoints. Typically, instruction breakpoints would be set from a disassembly window. \nTo clear all instruction breakpoints, specify an empty array.\nWhen an instruction breakpoint is hit, a 'stopped' event (with reason 'instruction breakpoint') is generated.\nClients should only call this request if the capability 'supportsInstructionBreakpoints' is true.",
"properties": {
"command": {
"type": "string",
Expand Down
1 change: 1 addition & 0 deletions crates/fuel-gas-price-algorithm/src/v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ impl AlgorithmUpdaterV1 {
if !height_range.is_empty() {
self.da_block_update(height_range, range_cost)?;
self.recalculate_projected_cost();
self.update_da_gas_price();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. Haha. I get it now... I think it makes sense either way but this probably better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should have some tests in the algo for this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addressed in 8ae983f

}
Ok(())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,166 @@ fn update_da_record_data__da_block_updates_projected_total_cost_with_known_and_g
let expected = new_known_total_cost + guessed_part;
assert_eq!(actual, expected as u128);
}

#[test]
fn update_da_record_data__da_block_lowers_da_gas_price() {
// given
let da_cost_per_byte = 40;
let da_recorded_block_height = 10;
let l2_block_height = 11;
let original_known_total_cost = 150;
let unrecorded_blocks = vec![BlockBytes {
height: 11,
block_bytes: 3000,
}];
let da_p_component = 2;
let guessed_cost: u64 = unrecorded_blocks
.iter()
.map(|block| block.block_bytes * da_cost_per_byte)
.sum();
let projected_total_cost = original_known_total_cost + guessed_cost;

let mut updater = UpdaterBuilder::new()
.with_da_cost_per_byte(da_cost_per_byte as u128)
.with_da_p_component(da_p_component)
.with_last_profit(10, 0)
.with_da_recorded_block_height(da_recorded_block_height)
.with_l2_block_height(l2_block_height)
.with_projected_total_cost(projected_total_cost as u128)
.with_known_total_cost(original_known_total_cost as u128)
.with_unrecorded_blocks(unrecorded_blocks.clone())
.build();

let new_cost_per_byte = 100;
let (recorded_heights, recorded_cost) =
unrecorded_blocks
.iter()
.fold((vec![], 0), |(mut range, cost), block| {
range.push(block.height);
(range, cost + block.block_bytes * new_cost_per_byte)
});
let min = recorded_heights.iter().min().unwrap();
let max = recorded_heights.iter().max().unwrap();
let recorded_range = *min..(max + 1);

let old_da_gas_price = updater.new_scaled_da_gas_price;

// when
updater
.update_da_record_data(recorded_range, recorded_cost as u128)
.unwrap();

// then
let new_da_gas_price = updater.new_scaled_da_gas_price;
// because the profit is 10 and the da_p_component is 2, the new da gas price should be lesser than the previous one.
assert_eq!(new_da_gas_price, 0);
assert_ne!(old_da_gas_price, new_da_gas_price);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be more specific at this level (and not just say it is different) You can copy most of the code from
update_l2_block_data__below_threshold_will_decrease_exec_gas_price, update_l2_block_data__above_threshold_will_increase_exec_gas_price, and update_l2_block_data__even_threshold_will_not_change_exec_gas_price

It feels redundant, but they are different endpoints so they change independently.

}

#[test]
fn update_da_record_data__da_block_increases_da_gas_price() {
// given
let da_cost_per_byte = 40;
let da_recorded_block_height = 10;
let l2_block_height = 11;
let original_known_total_cost = 150;
let unrecorded_blocks = vec![BlockBytes {
height: 11,
block_bytes: 3000,
}];
let da_p_component = 2;
let guessed_cost: u64 = unrecorded_blocks
.iter()
.map(|block| block.block_bytes * da_cost_per_byte)
.sum();
let projected_total_cost = original_known_total_cost + guessed_cost;

let mut updater = UpdaterBuilder::new()
.with_da_cost_per_byte(da_cost_per_byte as u128)
.with_da_p_component(da_p_component)
.with_last_profit(-10, 0)
.with_da_recorded_block_height(da_recorded_block_height)
.with_l2_block_height(l2_block_height)
.with_projected_total_cost(projected_total_cost as u128)
.with_known_total_cost(original_known_total_cost as u128)
.with_unrecorded_blocks(unrecorded_blocks.clone())
.build();

let new_cost_per_byte = 100;
let (recorded_heights, recorded_cost) =
unrecorded_blocks
.iter()
.fold((vec![], 0), |(mut range, cost), block| {
range.push(block.height);
(range, cost + block.block_bytes * new_cost_per_byte)
});
let min = recorded_heights.iter().min().unwrap();
let max = recorded_heights.iter().max().unwrap();
let recorded_range = *min..(max + 1);

let old_da_gas_price = updater.new_scaled_da_gas_price;

// when
updater
.update_da_record_data(recorded_range, recorded_cost as u128)
.unwrap();

// then
let new_da_gas_price = updater.new_scaled_da_gas_price;
// because the profit is -10 and the da_p_component is 2, the new da gas price should be greater than the previous one.
assert_eq!(new_da_gas_price, 6);
assert_ne!(old_da_gas_price, new_da_gas_price);
}

#[test]
fn update_da_record_data__da_block_will_not_change_da_gas_price() {
// given
let da_cost_per_byte = 40;
let da_recorded_block_height = 10;
let l2_block_height = 11;
let original_known_total_cost = 150;
let unrecorded_blocks = vec![BlockBytes {
height: 11,
block_bytes: 3000,
}];
let da_p_component = 2;
let guessed_cost: u64 = unrecorded_blocks
.iter()
.map(|block| block.block_bytes * da_cost_per_byte)
.sum();
let projected_total_cost = original_known_total_cost + guessed_cost;

let mut updater = UpdaterBuilder::new()
.with_da_cost_per_byte(da_cost_per_byte as u128)
.with_da_p_component(da_p_component)
.with_last_profit(0, 0)
.with_da_recorded_block_height(da_recorded_block_height)
.with_l2_block_height(l2_block_height)
.with_projected_total_cost(projected_total_cost as u128)
.with_known_total_cost(original_known_total_cost as u128)
.with_unrecorded_blocks(unrecorded_blocks.clone())
.build();

let new_cost_per_byte = 100;
let (recorded_heights, recorded_cost) =
unrecorded_blocks
.iter()
.fold((vec![], 0), |(mut range, cost), block| {
range.push(block.height);
(range, cost + block.block_bytes * new_cost_per_byte)
});
let min = recorded_heights.iter().min().unwrap();
let max = recorded_heights.iter().max().unwrap();
let recorded_range = *min..(max + 1);

let old_da_gas_price = updater.new_scaled_da_gas_price;

// when
updater
.update_da_record_data(recorded_range, recorded_cost as u128)
.unwrap();

// then
let new_da_gas_price = updater.new_scaled_da_gas_price;
assert_eq!(old_da_gas_price, new_da_gas_price);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ use crate::{
ports::MetadataStorage,
};
use fuel_core_storage::{
codec::{
postcard::Postcard,
Encode,
},
kv_store::KeyValueInspect,
structured_storage::StructuredStorage,
transactional::{
Expand Down Expand Up @@ -101,6 +105,8 @@ pub fn get_block_info(
height: (*block.header().height()).into(),
gas_used: used_gas,
block_gas_capacity: block_gas_limit,
block_bytes: Postcard::encode(block).len() as u64,
block_fees: fee,
};
Ok(info)
}
Expand Down
4 changes: 4 additions & 0 deletions crates/services/gas_price_service/src/common/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,9 @@ pub enum BlockInfo {
gas_used: u64,
// Total gas capacity of the block
block_gas_capacity: u64,
// The size of block in bytes
block_bytes: u64,
// The fees the block has collected
block_fees: u64,
},
}
3 changes: 3 additions & 0 deletions crates/services/gas_price_service/src/v0/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ where
height,
gas_used,
block_gas_capacity,
..
} => {
self.handle_normal_block(height, gas_used, block_gas_capacity)
.await?;
Expand Down Expand Up @@ -225,6 +226,8 @@ mod tests {
height: block_height,
gas_used: 60,
block_gas_capacity: 100,
block_bytes: 100,
block_fees: 100,
};

let (l2_block_sender, l2_block_receiver) = mpsc::channel(1);
Expand Down
4 changes: 4 additions & 0 deletions crates/services/gas_price_service/src/v0/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ async fn next_gas_price__affected_by_new_l2_block() {
height: 1,
gas_used: 60,
block_gas_capacity: 100,
block_bytes: 100,
block_fees: 100,
};
let (l2_block_sender, l2_block_receiver) = tokio::sync::mpsc::channel(1);
let l2_block_source = FakeL2BlockSource {
Expand Down Expand Up @@ -186,6 +188,8 @@ async fn next__new_l2_block_saves_old_metadata() {
height: 1,
gas_used: 60,
block_gas_capacity: 100,
block_bytes: 100,
block_fees: 100,
};
let (l2_block_sender, l2_block_receiver) = tokio::sync::mpsc::channel(1);
let l2_block_source = FakeL2BlockSource {
Expand Down
1 change: 1 addition & 0 deletions crates/services/gas_price_service/src/v1.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod algorithm;
pub mod da_source_service;
pub mod metadata;
pub mod service;
7 changes: 6 additions & 1 deletion crates/services/gas_price_service/src/v1/algorithm.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::common::gas_price_algorithm::GasPriceAlgorithm;
use crate::common::gas_price_algorithm::{
GasPriceAlgorithm,
SharedGasPriceAlgo,
};
use fuel_core_types::fuel_types::BlockHeight;
use fuel_gas_price_algorithm::v1::AlgorithmV1;

Expand All @@ -11,3 +14,5 @@ impl GasPriceAlgorithm for AlgorithmV1 {
self.worst_case(block_height.into())
}
}

pub type SharedV1Algorithm = SharedGasPriceAlgo<AlgorithmV1>;
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ pub mod service;

#[derive(Debug, Default, Clone, Eq, Hash, PartialEq)]
pub struct DaBlockCosts {
pub l2_block_range: core::ops::Range<u64>,
pub l2_block_range: core::ops::Range<u32>,
pub blob_size_bytes: u32,
pub blob_cost_wei: u128,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ trait BlockCommitterApi: Send + Sync {
/// Used to get the costs for a specific seqno
async fn get_costs_by_seqno(
&self,
number: u64,
number: u32,
) -> DaBlockCostsResult<Option<RawDaBlockCosts>>;
/// Used to get the costs for a range of blocks (inclusive)
async fn get_cost_bundles_by_range(
&self,
range: core::ops::Range<u64>,
range: core::ops::Range<u32>,
) -> DaBlockCostsResult<Vec<Option<RawDaBlockCosts>>>;
}

Expand All @@ -40,9 +40,9 @@ pub struct BlockCommitterDaBlockCosts<BlockCommitter> {
#[derive(Debug, Deserialize, Serialize, Clone, Default, PartialEq)]
pub struct RawDaBlockCosts {
/// Sequence number (Monotonically increasing nonce)
pub sequence_number: u64,
pub sequence_number: u32,
/// The range of blocks that the costs apply to
pub blocks_range: core::ops::Range<u64>,
pub blocks_range: core::ops::Range<u32>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to change this to just be a vec with these changes:
#2415

/// The DA block height of the last transaction for the range of blocks
pub da_block_height: DaBlockHeight,
/// Rolling sum cost of posting blobs (wei)
Expand Down Expand Up @@ -143,7 +143,7 @@ impl BlockCommitterApi for BlockCommitterHttpApi {

async fn get_costs_by_seqno(
&self,
number: u64,
number: u32,
) -> DaBlockCostsResult<Option<RawDaBlockCosts>> {
let response = self
.client
Expand All @@ -157,7 +157,7 @@ impl BlockCommitterApi for BlockCommitterHttpApi {

async fn get_cost_bundles_by_range(
&self,
range: core::ops::Range<u64>,
range: core::ops::Range<u32>,
) -> DaBlockCostsResult<Vec<Option<RawDaBlockCosts>>> {
let response = self
.client
Expand Down Expand Up @@ -192,23 +192,24 @@ mod tests {
}
async fn get_costs_by_seqno(
&self,
seq_no: u64,
seq_no: u32,
) -> DaBlockCostsResult<Option<RawDaBlockCosts>> {
// arbitrary logic to generate a new value
let mut value = self.value.clone();
if let Some(value) = &mut value {
value.sequence_number = seq_no;
value.blocks_range =
value.blocks_range.end * seq_no..value.blocks_range.end * seq_no + 10;
value.da_block_height = value.da_block_height + (seq_no + 1).into();
value.da_block_height =
value.da_block_height + ((seq_no + 1) as u64).into();
value.total_cost += 1;
value.total_size_bytes += 1;
}
Comment on lines 197 to 207
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a lot of unchecked arithmetic and casting going on here. How do you feel about switching to checked and into/from here?

Ok(value)
}
async fn get_cost_bundles_by_range(
&self,
_: core::ops::Range<u64>,
_: core::ops::Range<u32>,
) -> DaBlockCostsResult<Vec<Option<RawDaBlockCosts>>> {
Ok(vec![self.value.clone()])
}
Expand Down Expand Up @@ -286,7 +287,7 @@ mod tests {
}
async fn get_costs_by_seqno(
&self,
seq_no: u64,
seq_no: u32,
) -> DaBlockCostsResult<Option<RawDaBlockCosts>> {
// arbitrary logic to generate a new value
let mut value = self.value.clone();
Expand All @@ -301,7 +302,7 @@ mod tests {
}
async fn get_cost_bundles_by_range(
&self,
_: core::ops::Range<u64>,
_: core::ops::Range<u32>,
) -> DaBlockCostsResult<Vec<Option<RawDaBlockCosts>>> {
Ok(vec![self.value.clone()])
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use tokio::{

use crate::v1::da_source_service::DaBlockCosts;
pub use anyhow::Result;
use fuel_core_services::stream::BoxFuture;

#[derive(Clone)]
pub struct SharedState(Sender<DaBlockCosts>);
Expand Down
Loading
Loading