🐛 Bug
Gas estimation treats a block's last_version as exclusive when scanning transactions for block_min_inclusion_price, even though the surrounding block APIs and storage logic treat last_version as inclusive.
Relevant code in api/src/context.rs:
match self.get_gas_prices_and_used(
first,
last - first,
ledger_info.ledger_version.0,
user_use_case_spread_factor.is_some(),
) {
But get_gas_prices_and_used() interprets that second argument as a count/limit:
fn get_gas_prices_and_used(
&self,
start_version: Version,
limit: u64,
ledger_version: Version,
count_majority_use_case: bool,
) -> Result<(Vec<(u64, u64)>, Vec<BlockEndInfo>, Option<f32>)> {
if start_version > ledger_version || limit == 0 {
return Ok((vec![], vec![], None));
}
let limit = std::cmp::min(limit, ledger_version - start_version + 1);
let txns = self.db.get_transaction_iterator(start_version, limit)?;
let infos = self.db.get_transaction_info_iterator(start_version, limit)?;
...
}
The rest of the block stack treats last_version as inclusive:
// storage/aptosdb/src/db/aptosdb_internal.rs
Ok(next_block_info) => next_block_info.first_version() - 1,
// api/src/context.rs
(last_version - first_version + 1) as u16
That means the estimator currently scans [first, last) instead of [first, last] and drops last_version.
In normal committed blocks, last_version is typically the trailing BlockEpilogue. As a result, the estimator can miss BlockEndInfo::limit_reached() and incorrectly classify a full block as not full.
To reproduce
Code snippet to reproduce
let first = 100;
let last = 102; // inclusive block range [100, 102]
let current_limit = last - first; // 2
let expected_limit = last - first + 1; // 3
// current logic reads 2 transactions starting at 100,
// so version 102 is skipped entirely
Behavioral path
} else if !block_end_infos.is_empty() {
assert_eq!(1, block_end_infos.len());
block_end_infos.first().unwrap().limit_reached()
}
If the skipped last_version is the block-ending BlockEpilogue, block_end_infos stays empty and full-block detection falls back to weaker heuristics.
Stack trace/error message
No runtime error; this is a logic bug in block range arithmetic.
Expected Behavior
Gas estimation should read the full inclusive block span, including last_version, so the block-ending BlockEpilogue is visible and limit_reached() is evaluated correctly.
System information
Please complete the following information:
- Aptos Core Version:
main at current HEAD
- Rust Version: not checked
- Computer OS: macOS
Additional context
Suggested fix:
let limit = last
.checked_sub(first)
.map(|delta| delta + 1)
.unwrap_or(0);
match self.get_gas_prices_and_used(
first,
limit,
ledger_info.ledger_version.0,
user_use_case_spread_factor.is_some(),
) {
...
}
Suggested regression tests:
- estimator reads the full inclusive block span
- block-ending
BlockEpilogue is observed by gas estimation
- full-block detection respects
limit_reached() from the trailing epilogue
🐛 Bug
Gas estimation treats a block's
last_versionas exclusive when scanning transactions forblock_min_inclusion_price, even though the surrounding block APIs and storage logic treatlast_versionas inclusive.Relevant code in
api/src/context.rs:But
get_gas_prices_and_used()interprets that second argument as a count/limit:The rest of the block stack treats
last_versionas inclusive:That means the estimator currently scans
[first, last)instead of[first, last]and dropslast_version.In normal committed blocks,
last_versionis typically the trailingBlockEpilogue. As a result, the estimator can missBlockEndInfo::limit_reached()and incorrectly classify a full block as not full.To reproduce
Code snippet to reproduce
Behavioral path
If the skipped
last_versionis the block-endingBlockEpilogue,block_end_infosstays empty and full-block detection falls back to weaker heuristics.Stack trace/error message
Expected Behavior
Gas estimation should read the full inclusive block span, including
last_version, so the block-endingBlockEpilogueis visible andlimit_reached()is evaluated correctly.System information
Please complete the following information:
mainat current HEADAdditional context
Suggested fix:
Suggested regression tests:
BlockEpilogueis observed by gas estimationlimit_reached()from the trailing epilogue