Skip to content

Commit d386e90

Browse files
authored
Improved block gas limit - output size limit, conflict aware, io/compute multipliers (aptos-labs#10943)
throughput changes based on whether there are conflicts between transactions (and they need to be executed sequentially), or if they are parallel. But the gas charged stays constant, as gas charging is independent for each transaction. In order to limit to the total amount of time block can be executing, we introduce conflict-aware block gas limit - where we multiply gas used for individual transactions with the coefficient of how many of the recent 8 transaction it had conflicts with (including self, which we assume it had conflict with - to have the number in the [1, 8] range)
1 parent 0ed5618 commit d386e90

File tree

23 files changed

+1444
-475
lines changed

23 files changed

+1444
-475
lines changed

Cargo.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/src/context.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,8 +1029,14 @@ impl Context {
10291029
} else if let Some(full_block_gas_used) =
10301030
block_config.block_gas_limit_type.block_gas_limit()
10311031
{
1032-
prices_and_used.iter().map(|(_, used)| *used).sum::<u64>()
1033-
>= full_block_gas_used
1032+
// be pessimistic for conflicts, as such information is not onchain
1033+
let gas_used = prices_and_used.iter().map(|(_, used)| *used).sum::<u64>();
1034+
let max_conflict_multiplier = block_config
1035+
.block_gas_limit_type
1036+
.conflict_penalty_window()
1037+
.unwrap_or(1)
1038+
as u64;
1039+
gas_used * max_conflict_multiplier >= full_block_gas_used
10341040
} else {
10351041
false
10361042
};

aptos-move/aptos-vm-types/src/change_set.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,6 @@ impl VMChangeSet {
460460
.collect::<anyhow::Result<BTreeMap<StateKey, WriteOp>, VMStatus>>()?;
461461
self.aggregator_v1_write_set
462462
.extend(materialized_aggregator_delta_set);
463-
464463
Ok(())
465464
}
466465

aptos-move/aptos-vm/src/block_executor/mod.rs

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use aptos_aggregator::{
1515
use aptos_block_executor::{
1616
errors::Error, executor::BlockExecutor,
1717
task::TransactionOutput as BlockExecutorTransactionOutput,
18-
txn_commit_hook::TransactionCommitHook,
18+
txn_commit_hook::TransactionCommitHook, types::InputOutputKey,
1919
};
2020
use aptos_infallible::Mutex;
2121
use aptos_state_view::{StateView, StateViewId};
@@ -36,7 +36,10 @@ use aptos_vm_types::{abstract_write_op::AbstractResourceWriteOp, output::VMOutpu
3636
use move_core_types::{language_storage::StructTag, value::MoveTypeLayout, vm_status::VMStatus};
3737
use once_cell::sync::OnceCell;
3838
use rayon::ThreadPool;
39-
use std::{collections::BTreeMap, sync::Arc};
39+
use std::{
40+
collections::{BTreeMap, HashSet},
41+
sync::Arc,
42+
};
4043

4144
/// Output type wrapper used by block executor. VM output is stored first, then
4245
/// transformed into TransactionOutput type that is returned.
@@ -316,6 +319,61 @@ impl BlockExecutorTransactionOutput for AptosTransactionOutput {
316319
.expect("Output to be set to get fee statement")
317320
.fee_statement()
318321
}
322+
323+
fn output_approx_size(&self) -> u64 {
324+
let vm_output = self.vm_output.lock();
325+
let change_set = vm_output
326+
.as_ref()
327+
.expect("Output to be set to get write summary")
328+
.change_set();
329+
330+
let mut size = 0;
331+
for (state_key, write_size) in change_set.write_set_size_iter() {
332+
size += state_key.size() as u64 + write_size.write_len().unwrap_or(0);
333+
}
334+
335+
for (event, _) in change_set.events() {
336+
size += event.size() as u64;
337+
}
338+
339+
size
340+
}
341+
342+
fn get_write_summary(&self) -> HashSet<InputOutputKey<StateKey, StructTag, DelayedFieldID>> {
343+
let vm_output = self.vm_output.lock();
344+
let change_set = vm_output
345+
.as_ref()
346+
.expect("Output to be set to get write summary")
347+
.change_set();
348+
349+
let mut writes = HashSet::new();
350+
351+
for (state_key, write) in change_set.resource_write_set() {
352+
match write {
353+
AbstractResourceWriteOp::Write(_)
354+
| AbstractResourceWriteOp::WriteWithDelayedFields(_) => {
355+
writes.insert(InputOutputKey::Resource(state_key.clone()));
356+
},
357+
AbstractResourceWriteOp::WriteResourceGroup(write) => {
358+
for tag in write.inner_ops().keys() {
359+
writes.insert(InputOutputKey::Group(state_key.clone(), tag.clone()));
360+
}
361+
},
362+
AbstractResourceWriteOp::InPlaceDelayedFieldChange(_)
363+
| AbstractResourceWriteOp::ResourceGroupInPlaceDelayedFieldChange(_) => {
364+
// No conflicts on resources from in-place delayed field changes.
365+
// Delayed fields conflicts themselves are handled via
366+
// delayed_field_change_set below.
367+
},
368+
}
369+
}
370+
371+
for identifier in change_set.delayed_field_change_set().keys() {
372+
writes.insert(InputOutputKey::DelayedField(*identifier));
373+
}
374+
375+
writes
376+
}
319377
}
320378

321379
pub struct BlockAptosVM();

aptos-move/block-executor/src/captured_reads.rs

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright © Aptos Foundation
22
// SPDX-License-Identifier: Apache-2.0
33

4+
use crate::types::InputOutputKey;
45
use anyhow::bail;
56
use aptos_aggregator::{
67
delta_math::DeltaHistory,
@@ -335,8 +336,6 @@ impl<T: Transaction> CapturedReads<T> {
335336
&'a self,
336337
skip: &'a HashSet<T::Key>,
337338
) -> impl Iterator<Item = (&T::Key, &GroupRead<T>)> {
338-
// TODO[agg_v2](optimize) - We could potentially filter out inner_reads
339-
// to only contain those that have Some(layout)
340339
self.group_reads.iter().filter(|(key, group_read)| {
341340
!skip.contains(key)
342341
&& group_read
@@ -662,6 +661,37 @@ impl<T: Transaction> CapturedReads<T> {
662661
Ok(true)
663662
}
664663

664+
pub(crate) fn get_read_summary(
665+
&self,
666+
) -> HashSet<InputOutputKey<T::Key, T::Tag, T::Identifier>> {
667+
let mut ret = HashSet::new();
668+
for (key, read) in &self.data_reads {
669+
if let DataRead::Versioned(_, _, _) = read {
670+
ret.insert(InputOutputKey::Resource(key.clone()));
671+
}
672+
}
673+
674+
for (key, group_reads) in &self.group_reads {
675+
for (tag, read) in &group_reads.inner_reads {
676+
if let DataRead::Versioned(_, _, _) = read {
677+
ret.insert(InputOutputKey::Group(key.clone(), tag.clone()));
678+
}
679+
}
680+
}
681+
682+
for key in &self.module_reads {
683+
ret.insert(InputOutputKey::Resource(key.clone()));
684+
}
685+
686+
for (key, read) in &self.delayed_field_reads {
687+
if let DelayedFieldRead::Value { .. } = read {
688+
ret.insert(InputOutputKey::DelayedField(*key));
689+
}
690+
}
691+
692+
ret
693+
}
694+
665695
pub(crate) fn mark_failure(&mut self) {
666696
self.speculative_failure = true;
667697
}
@@ -671,6 +701,42 @@ impl<T: Transaction> CapturedReads<T> {
671701
}
672702
}
673703

704+
#[derive(Derivative)]
705+
#[derivative(Default(bound = "", new = "true"))]
706+
pub(crate) struct UnsyncReadSet<T: Transaction> {
707+
pub(crate) resource_reads: HashSet<T::Key>,
708+
pub(crate) module_reads: HashSet<T::Key>,
709+
pub(crate) group_reads: HashMap<T::Key, HashSet<T::Tag>>,
710+
pub(crate) delayed_field_reads: HashSet<T::Identifier>,
711+
}
712+
713+
impl<T: Transaction> UnsyncReadSet<T> {
714+
pub(crate) fn get_read_summary(
715+
&self,
716+
) -> HashSet<InputOutputKey<T::Key, T::Tag, T::Identifier>> {
717+
let mut ret = HashSet::new();
718+
for key in &self.resource_reads {
719+
ret.insert(InputOutputKey::Resource(key.clone()));
720+
}
721+
722+
for (key, group_reads) in &self.group_reads {
723+
for tag in group_reads {
724+
ret.insert(InputOutputKey::Group(key.clone(), tag.clone()));
725+
}
726+
}
727+
728+
for key in &self.module_reads {
729+
ret.insert(InputOutputKey::Resource(key.clone()));
730+
}
731+
732+
for key in &self.delayed_field_reads {
733+
ret.insert(InputOutputKey::DelayedField(*key));
734+
}
735+
736+
ret
737+
}
738+
}
739+
674740
#[cfg(test)]
675741
mod test {
676742
use super::*;

0 commit comments

Comments
 (0)