Skip to content

Commit

Permalink
Fix a bug where post-VM gas cost not capped by gas budget (MystenLabs…
Browse files Browse the repository at this point in the history
  • Loading branch information
lxfind authored Feb 23, 2022
1 parent af77eae commit a4b9740
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 4 deletions.
18 changes: 16 additions & 2 deletions sui_programmability/adapter/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,22 @@ fn execute_internal<
// Cap total_gas by gas_budget in the fail case.
return ExecutionStatus::new_failure(cmp::min(total_gas, gas_budget), err);
}
ExecutionStatus::Success {
gas_used: total_gas,
// gas_budget should be enough to pay not only the VM excution cost,
// but also the cost to process all events, such as transfers.
if total_gas > gas_budget {
ExecutionStatus::new_failure(
gas_budget,
SuiError::InsufficientGas {
error: format!(
"Total gas used ({}) exceeds gas budget ({})",
total_gas, gas_budget
),
},
)
} else {
ExecutionStatus::Success {
gas_used: total_gas,
}
}
}
// charge for all computations so far
Expand Down
23 changes: 21 additions & 2 deletions sui_programmability/adapter/src/unit_tests/adapter_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,9 @@ fn test_move_call_insufficient_gas() {
let mut storage = InMemoryStorage::new(genesis_objects);

// 0. Create a gas object for gas payment.
let gas_object_id = ObjectID::random();
let gas_object =
Object::with_id_owner_for_testing(ObjectID::random(), base_types::SuiAddress::default());
Object::with_id_owner_for_testing(gas_object_id, base_types::SuiAddress::default());
storage.write_object(gas_object.clone());
storage.flush();

Expand All @@ -499,12 +500,30 @@ fn test_move_call_insufficient_gas() {
20, // This budget is not enough to execute all bytecode.
Vec::new(),
Vec::new(),
pure_args,
pure_args.clone(),
);
let err = response.unwrap().unwrap_err();
assert!(err.1.to_string().contains("VMError with status OUT_OF_GAS"));
// Provided gas_budget will be deducted as gas.
assert_eq!(err.0, 20);

// Trying again with a different gas budget.
let gas_object = storage.read_object(&gas_object_id).unwrap();
let response = call(
&mut storage,
&native_functions,
"ObjectBasics",
"create",
gas_object,
50, // This budget is enough to execute bytecode, but not enough for processing transfer events.
Vec::new(),
Vec::new(),
pure_args,
);
let err = response.unwrap().unwrap_err();
assert!(matches!(err.1, SuiError::InsufficientGas { .. }));
// Provided gas_budget will be deducted as gas.
assert_eq!(err.0, 50);
}

#[test]
Expand Down

0 comments on commit a4b9740

Please sign in to comment.