-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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): update block committer da source with established contract #2265
Conversation
fix: remove block height from error
463604c
to
b47bf54
Compare
if let Some(last_value) = &self.last_value { | ||
res = DaBlockCosts { | ||
l2_block_range: response.blocks_range.clone(), | ||
blob_size_bytes: response | ||
.total_size_bytes | ||
.checked_sub(last_value.total_size_bytes) | ||
.ok_or(anyhow!("Blob size bytes underflow"))?, | ||
blob_cost_wei: response | ||
.total_cost | ||
.checked_sub(last_value.total_cost) | ||
.ok_or(anyhow!("Blob cost wei underflow"))?, | ||
}; | ||
} else { | ||
res = DaBlockCosts { | ||
l2_block_range: response.blocks_range.clone(), | ||
blob_size_bytes: response.total_size_bytes, | ||
blob_cost_wei: response.total_cost, | ||
}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MitchTurner if the block committer da block cost source is starting up for the first time, we will still get the total_size_bytes
and total_cost
from the block committer. is it reasonable to expect the consumers of this service to persist state and detect the first value that this source spits out? Or should we include the last_state
in the new
fn that constructs the BlockCommitterDaBlockCosts
? I might lean to the latter approach since it is more testable, and allows consumers to actually bring their own persistence method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The consumers shouldn't need to know that info. They should just get the info for each committed batch. So the second sounds like a promising approach.
b3680c1
to
e488068
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bunch of little things.
@@ -24,7 +24,7 @@ pub const POLLING_INTERVAL_MS: u64 = 10_000; | |||
|
|||
#[derive(Debug, Default, Clone, Eq, Hash, PartialEq)] | |||
pub struct DaBlockCosts { | |||
pub l2_block_range: core::ops::Range<u32>, | |||
pub l2_block_range: core::ops::Range<u64>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why u64
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's because the sequence number is u64
as we decided. the type DaBlockHeight
is also u64
async fn get_bundles_by_range( | ||
&self, | ||
range: core::ops::Range<u64>, | ||
) -> DaBlockCostsResult<Vec<Option<RawDaBlockCosts>>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing a docstring.
But I'm also unsure what the expected behavior is here. Like if a bundle included a range of blocks 50 -> 100, what would you get back if you asked for range 75 -> 100 or 75 -> 125?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its an inclusive range, so I assume we should actually increment by 1. We aren't using this yet, but it will be a part of a more comprehensive solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed docstring in 5330975
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its an inclusive range
I'm not sure if this answered my question. The committer doesn't have data for individual blocks, just bundles.
Are you saying that if I asked for 50..100 and the existing bundles are 25..75 and 75..125, I would get those two bundles back? or nothing, since my requested range didn't encompass any full bundle?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should rope in @MujkicA here. it shouldn't return anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the issue on the committer side, probably better if we move this discussion there:
url: Url, | ||
pub struct BlockCommitterDaBlockCosts<BlockCommitter> { | ||
client: BlockCommitter, | ||
last_value: Option<RawDaBlockCosts>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The algorithm currently expects things in order. I'm not suggesting we change anything, I'm just wondering if it would make more sense to have the checks all in one place or the other. We could check that everything is correct here and do no checks in the algo. I'm not sure what makes the most sense, but worth thinking about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea, we should have data validation, but that should be limited to the scope of the block committer data source. it can't know what data is expected on the receiver end, but it can atleast guarantee some things. we can choose to decouple business logic from this service, that will allow some flexibility on consumers of this data.
// assert_eq!(initial.blob_size_bytes, updated.blob_size_bytes); | ||
// assert_eq!(initial.blob_cost_wei, updated.blob_cost_wei); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in b5e7cbd
#[tokio::test] | ||
async fn request_da_block_cost__when_response_is_none__then_error() { | ||
// given | ||
let mock_block_committer = MockBlockCommitterApi::new(None); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These names are confusing. Maybe mock_api
to differentiate it from the block_committer
.
This applies to all the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in 28ba81f
block_committer_da_block_costs, | ||
DaBlockCosts { | ||
l2_block_range: da_block_costs.blocks_range.clone(), | ||
blob_size_bytes: da_block_costs.total_size_bytes, | ||
blob_cost_wei: da_block_costs.total_cost, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: rename block_committer_da_block_costs
to actual
and the DaBlockCosts
to expected
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in 9ea0a9c
url: Url, | ||
pub struct BlockCommitterDaBlockCosts<BlockCommitter> { | ||
client: BlockCommitter, | ||
last_value: Option<RawDaBlockCosts>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: rename this to last_raw_da_block_costs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in 7d18c22
BlockCommitter: BlockCommitterApi, | ||
{ | ||
async fn request_da_block_cost(&mut self) -> DaBlockCostsResult<DaBlockCosts> { | ||
let response; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: rename raw_da_block_costs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in d545341
} | ||
|
||
if let Some(response) = response { | ||
let res; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: rename da_block_costs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in d545341
|
||
if let Some(response) = response { | ||
let res; | ||
if let Some(last_value) = &self.last_value { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I think I prefer to only have one if let Some(last_value) = &self.last_value
and have redundant if let Some(response) = response
in each branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub blob_size_bytes: u32, | ||
pub blob_cost: u128, | ||
pub struct RawDaBlockCosts { | ||
// Sequence number (Monotonically increasing nonce) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Sequence number (Monotonically increasing nonce) | |
/// Sequence number (Monotonically increasing nonce) |
Same for other fields?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in 5330975
e488068
to
23a41fa
Compare
&self, | ||
number: u64, | ||
) -> DaBlockCostsResult<Option<RawDaBlockCosts>>; | ||
async fn get_bundles_by_range( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think adding costs
somewhere to the name would make it easier to relate this function to the other two.
E.g. get_cost_bundles_by_range
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in 552d224
@@ -1,3 +1,6 @@ | |||
#![allow(non_snake_case)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can remove this line and add #[allow(non_snake_case)]
just before the mod tests
declaration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in d562d72
} | ||
self.last_value = Some(response.clone()); | ||
Ok(res) | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can use the let - else syntax to improve code readability:
let Some(response) = response else { return Err(anyhow!("No response from block committer")) };
/* Now you can have the code in the if branch here */
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in edfc1ff
async fn request_da_block_cost(&mut self) -> DaBlockCostsResult<DaBlockCosts> { | ||
let response; | ||
|
||
if let Some(last_value) = &self.last_value { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can pattern match to improve readability. To avoid moving last_value
out of the option, you can either pattern match on self.last_value.as_ref()
, or use the ref
syntax.
let response = match self.last_value {
Some(ref last_value) => self
.client
.get_costs_by_seqno(last_value.sequence_number + 1),
_ => self.client.get_latest_costs(),
}
.await?;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in 2893288
|
||
if let Some(response) = response { | ||
let res; | ||
if let Some(last_value) = &self.last_value { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you iter
over the Option
, you can use the .fold
function to remove some code duplication and make the code a bit more clear.
I played a bit with your code and ended up with the following:
let Some(ref response) = response else {
return Err(anyhow!("No response from block committer"))
};
let res = self.last_value.iter().fold(
Ok(response.into()),
|costs: DaBlockCostsResult<DaBlockCosts>, last_value| {
let costs = costs.expect("Defined to be OK");
let blob_size_bytes = costs
.blob_size_bytes
.checked_sub(last_value.total_size_bytes)
.ok_or(anyhow!("Blob size bytes underflow"))?;
let blob_cost_wei = response
.total_cost
.checked_sub(last_value.total_cost)
.ok_or(anyhow!("Blob cost wei underflow"))?;
Ok(DaBlockCosts {
blob_size_bytes,
blob_cost_wei,
..costs
})
},
)?;
self.last_value = Some(response.clone());
Ok(res)
This requires to implement From<&RawDaBlockCosts> for DaBlockCosts
.
impl From<&RawDaBlockCosts> for DaBlockCosts {
fn from(raw_da_block_costs: &RawDaBlockCosts) -> Self {
DaBlockCosts {
l2_block_range: raw_da_block_costs.blocks_range.clone(),
blob_size_bytes: raw_da_block_costs.total_size_bytes,
blob_cost_wei: raw_da_block_costs.total_cost,
}
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in edfc1ff
2893288
to
e97c3f9
Compare
let result = block_committer.request_da_block_cost().await; | ||
|
||
// then | ||
assert!(result.is_err()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was gonna say we should check the specific error variant here but anyhow
:(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in my own experience, I tend to prefer thiserror::Error
to anyhow
by a lot, especially in codebases where each module has its own error type.
let mut block_committer = BlockCommitterDaBlockCosts::new(mock_api, None); | ||
|
||
// when | ||
let actual = block_committer.request_da_block_cost().await.unwrap(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this part of the setup? I don't think we need to do any checks on this value and it can be moved to given
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in 0794465
|
||
// then | ||
assert!(result.is_err()); | ||
assert!(block_committer.last_raw_da_block_costs.is_none()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this check is unnecessary. From the outside observer, we don't care what is being set internally, just the external result of those internal values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in 931adfe
|
||
// then | ||
assert_eq!(actual, expected); | ||
assert!(block_committer.last_raw_da_block_costs.is_some()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also unnecessary I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in fd44dd4
fd44dd4
to
3f3c251
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
## Version v0.37.0 ### Added - [1609](#1609): Add DA compression support. Compressed blocks are stored in the offchain database when blocks are produced, and can be fetched using the GraphQL API. - [2290](#2290): Added a new CLI argument `--graphql-max-directives`. The default value is `10`. - [2195](#2195): Added enforcement of the limit on the size of the L2 transactions per block according to the `block_transaction_size_limit` parameter. - [2131](#2131): Add flow in TxPool in order to ask to newly connected peers to share their transaction pool - [2182](#2151): Limit number of transactions that can be fetched via TxSource::next - [2189](#2151): Select next DA height to never include more than u16::MAX -1 transactions from L1. - [2162](#2162): Pool structure with dependencies, etc.. for the next transaction pool module. Also adds insertion/verification process in PoolV2 and tests refactoring - [2265](#2265): Integrate Block Committer API for DA Block Costs. - [2280](#2280): Allow comma separated relayer addresses in cli - [2299](#2299): Support blobs in the predicates. - [2300](#2300): Added new function to `fuel-core-client` for checking whether a blob exists. ### Changed #### Breaking - [2299](#2299): Anyone who wants to participate in the transaction broadcasting via p2p must upgrade to support new predicates on the TxPool level. - [2299](#2299): Upgraded `fuel-vm` to `0.58.0`. More information in the [release](https://github.com/FuelLabs/fuel-vm/releases/tag/v0.58.0). - [2276](#2276): Changed how complexity for blocks is calculated. The default complexity now is 80_000. All queries that somehow touch the block header now are more expensive. - [2290](#2290): Added a new GraphQL limit on number of `directives`. The default value is `10`. - [2206](#2206): Use timestamp of last block when dry running transactions. - [2153](#2153): Updated default gas costs for the local testnet configuration to match `fuel-core 0.35.0`. ## What's Changed * fix: use core-test.fuellabs.net for dnsaddr resolution by @rymnc in #2214 * Removed state transition bytecode from the local testnet by @xgreenx in #2215 * Send whole transaction pool upon subscription to gossip by @AurelienFT in #2131 * Update default gas costs based on 0.35.0 benchmarks by @xgreenx in #2153 * feat: Use timestamp of last block when dry running transactions by @netrome in #2206 * fix(dnsaddr_resolution): use fqdn separator to prevent suffixing by dns resolvers by @rymnc in #2222 * TransactionSource: specify maximum number of transactions to be fetched by @acerone85 in #2182 * Implement worst case scenario for price algorithm v1 by @rafal-ch in #2219 * chore(gas_price_service): define port for L2 data by @rymnc in #2224 * Block producer selects da height to never exceed u64::MAX - 1 transactions from L1 by @acerone85 in #2189 * Weekly `cargo update` by @github-actions in #2236 * Use fees to calculate DA reward and avoid issues with Gwei/Wei conversions by @MitchTurner in #2229 * Protect against passing `i128::MIN` to `abs()` which causes overflow by @rafal-ch in #2241 * Acquire `da_finalization_period` from the command line by @rafal-ch in #2240 * Executor: test Tx_count limit with incorrect tx source by @acerone85 in #2242 * Minor updates to docs + a few typos fixed by @rafal-ch in #2250 * chore(gas_price_service): move algorithm_updater to fuel-core-gas-price-service by @rymnc in #2246 * Use single heavy input in the `transaction_throughput.rs` benchmarks by @xgreenx in #2205 * Enforce the block size limit by @rafal-ch in #2195 * feat: build ARM and AMD in parallel by @mchristopher in #2130 * Weekly `cargo update` by @github-actions in #2268 * chore(gas_price_service): split into v0 and v1 and squash FuelGasPriceUpdater type into GasPriceService by @rymnc in #2256 * feat(gas_price_service): update block committer da source with established contract by @rymnc in #2265 * Use bytes from `unrecorded_blocks` rather from the block from DA by @MitchTurner in #2252 * TxPool v2 General architecture by @AurelienFT in #2162 * Add value delimiter and tests args by @AurelienFT in #2280 * fix(da_block_costs): remove Arc<Mutex<>> on shared_state and expose channel by @rymnc in #2278 * fix(combined_database): syncing auxiliary databases on startup with custom behaviour by @rymnc in #2272 * fix: Manually encode Authorization header for eventsource_client by @Br1ght0ne in #2284 * Address `async-graphql` vulnerability by @MitchTurner in #2290 * Update the WASM compatibility tests for `0.36` release by @rafal-ch in #2271 * DA compression by @Dentosal in #1609 * Use different port for every version compatibility test by @rafal-ch in #2301 * Fix block query complexity by @xgreenx in #2297 * Support blobs in predicates by @Voxelot in #2299 **Full Changelog**: v0.36.0...v0.37.0
Note
This is PR 7/7 for #2139
Linked Issues/PRs
Description
Updates the
BlockCommitterApi
to implement the contract established with us and the block committer team. There is some business logic that is slightly unclear, need @MitchTurner for insights.Checklist
Before requesting review
After merging, notify other teams
[Add or remove entries as needed]