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

fix(node): Take 'wait' syscall into account in calculate_gas_info #3609

Merged
merged 6 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions pallets/gear/src/runtime_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,6 @@ where
}
};

let dispatch_id = queued_dispatch.id();
let success_reply = queued_dispatch
.reply_details()
.map(|rd| rd.to_reply_code().is_success())
Expand Down Expand Up @@ -211,8 +210,22 @@ where
for note in journal {
core_processor::handle_journal(vec![note.clone()], &mut ext_manager);

if let Some(remaining_gas) = get_main_limit() {
min_limit = min_limit.max(initial_gas.saturating_sub(remaining_gas));
match get_main_limit() {
Some(remaining_gas) => {
min_limit = min_limit.max(initial_gas.saturating_sub(remaining_gas))
}
None => match note {
// take into account that 'wait' syscall greedily consumes all available gas.
// 'wait_for' and 'wait_up_to' should not consume all available gas
// because of the limited durations. If a duration is a big enough then it
// won't matter how to calculate the limit: it will be the same.
JournalNote::WaitDispatch { ref dispatch, .. }
breathx marked this conversation as resolved.
Show resolved Hide resolved
if from_main_chain(dispatch.id())? =>
{
min_limit = initial_gas
}
_ => (),
},
}

match note {
Expand Down
88 changes: 78 additions & 10 deletions pallets/gear/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8001,18 +8001,9 @@ fn locking_gas_for_waitlist() {
use demo_constructor::{Calls, Scheme};
use demo_gas_burned::WASM_BINARY as GAS_BURNED_BINARY;

let wat = r#"
(module
(import "env" "memory" (memory 1))
(import "env" "gr_wait" (func $gr_wait))
(export "handle" (func $handle))
(func $handle call $gr_wait)
)"#;

init_logger();
new_test_ext().execute_with(|| {
// This program just waits on each handle message.
let waiter = upload_program_default(USER_1, ProgramCodeKind::Custom(wat))
let waiter = upload_program_default(USER_1, ProgramCodeKind::Custom(utils::WAITER_WAT))
.expect("submit result was asserted");

// This program just does some calculations (burns gas) on each handle message.
Expand Down Expand Up @@ -15193,6 +15184,75 @@ fn test_constructor_if_else() {
});
}

#[test]
fn calculate_gas_wait() {
use demo_constructor::{Calls, Scheme};

init_logger();
new_test_ext().execute_with(|| {
let waiter = upload_program_default(USER_1, ProgramCodeKind::Custom(WAITER_WAT))
.expect("submit result was asserted");

let (_init_mid, sender) =
submit_constructor_with_args(USER_1, DEFAULT_SALT, Scheme::empty(), 0);

run_to_next_block(None);

assert!(Gear::is_initialized(waiter));
assert!(Gear::is_initialized(sender));

let calls = Calls::builder().send(waiter.into_bytes(), []);

let allow_other_panics = true;
let allow_skip_zero_replies = true;
let GasInfo { burned, .. } = Gear::calculate_gas_info(
USER_1.into_origin(),
HandleKind::Handle(sender),
calls.encode(),
0,
allow_other_panics,
allow_skip_zero_replies,
)
.expect("calculate_gas_info failed");

let cost = CostsPerBlockOf::<Test>::waitlist();
let GasInfo {
min_limit: limit_no_rent,
..
} = Gear::run_with_ext_copy(|| {
Gear::calculate_gas_info_impl(
USER_1.into_origin(),
HandleKind::Handle(sender),
burned + cost - 1,
calls.encode(),
0,
allow_other_panics,
allow_skip_zero_replies,
None,
)
})
.expect("calculate_gas_info failed");

let GasInfo { min_limit, .. } = Gear::run_with_ext_copy(|| {
Gear::calculate_gas_info_impl(
USER_1.into_origin(),
HandleKind::Handle(sender),
burned + 1_000_000 * cost,
calls.encode(),
0,
allow_other_panics,
allow_skip_zero_replies,
None,
)
})
.expect("calculate_gas_info failed");

// 'wait' syscall greedely consumes all available gas so
// calculated limits should not be equal
assert!(min_limit > limit_no_rent);
});
}

mod utils {
#![allow(unused)]

Expand Down Expand Up @@ -15234,6 +15294,14 @@ mod utils {
pub(super) const DEFAULT_SALT: &[u8; 4] = b"salt";
pub(super) const EMPTY_PAYLOAD: &[u8; 0] = b"";
pub(super) const OUTGOING_WITH_VALUE_IN_HANDLE_VALUE_GAS: u64 = 10000000;
// This program just waits on each handle message.
pub(super) const WAITER_WAT: &str = r#"
(module
(import "env" "memory" (memory 1))
(import "env" "gr_wait" (func $gr_wait))
(export "handle" (func $handle))
(func $handle call $gr_wait)
)"#;

pub(super) type DispatchCustomResult<T> = Result<T, DispatchErrorWithPostInfo>;
pub(super) type AccountId = <Test as frame_system::Config>::AccountId;
Expand Down