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

Deferred_calls #335

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 10 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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ chrono = { version = "=0.4", features = ["clock"], default-features = false }
displaydoc = "0.2"
function_name = "0.3"
loupe = "0.1"
#massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs.git", rev = "426fd325a55dfcc4033920bed2de075a7e7ad4b7" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happened here ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs.git", rev = "38950875a7aa406fedc4f0b8336864e5ff290f2c" }
more-asserts = "0.3"
num_enum = "0.7"
Expand Down
143 changes: 143 additions & 0 deletions src/as_execution/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,149 @@ pub(crate) fn assembly_script_chain_id(mut ctx: FunctionEnvMut<ASEnv>) -> ABIRes
Ok(chain_id as u64)
}

/// Return the price in nMAS to book an deferred call space in a specific slot.
#[named]
pub(crate) fn assembly_script_get_deferred_call_quote(
mut ctx: FunctionEnvMut<ASEnv>,
deferred_call_period: i64,
deferred_call_thread: i32,
max_gas: i64,
) -> ABIResult<u64> {
let env = get_env(&ctx)?;
sub_remaining_gas_abi(&env, &mut ctx, function_name!())?;
let asc_slot: (u64, u8) = match (
deferred_call_period.try_into(),
deferred_call_thread.try_into(),
) {
(Ok(p), Ok(t)) => (p, t),
(Err(_), _) => abi_bail!("negative validity end period"),
(_, Err(_)) => abi_bail!("invalid validity end thread"),
};
if max_gas.is_negative() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

best practice: better do a try_into u64 directly since below we convert using "as u64"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

abi_bail!("negative max gas");
}
let (available, mut price) = env
.get_interface()
.deferred_call_quote(asc_slot, max_gas as u64)?;
if !available {
price = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If !available, why don't we abi_bail!() instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because it's a quote, not a reservation attempt

}
#[cfg(feature = "execution-trace")]
ctx.data_mut().trace.push(AbiTrace {
name: function_name!().to_string(),
params: vec![
into_trace_value!(deferred_call_period),
into_trace_value!(deferred_call_thread),
into_trace_value!(max_gas),
],
return_value: price.into(),
sub_calls: None,
});
Ok(price)
}

/// Register a new deferred call in the target slot with the given parameters.
#[named]
#[allow(clippy::too_many_arguments)]
pub(crate) fn assembly_script_deferred_call_register(
mut ctx: FunctionEnvMut<ASEnv>,
target_address: i32,
target_function: i32,
target_period: i64,
target_thread: i32,
max_gas: i64,
raw_coins: i64,
params: i32,
) -> ABIResult<i32> {
let env = get_env(&ctx)?;
sub_remaining_gas_abi(&env, &mut ctx, function_name!())?;
let asc_target_slot: (u64, u8) = match (target_period.try_into(), target_thread.try_into()) {
(Ok(p), Ok(t)) => (p, t),
(Err(_), _) => abi_bail!("negative validity end period"),
(_, Err(_)) => abi_bail!("invalid validity end thread"),
};
if max_gas.is_negative() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try_into u64

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

abi_bail!("negative max gas");
}
if raw_coins.is_negative() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try into u64

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

abi_bail!("negative coins")
}
let memory = get_memory!(env);
let target_address = read_string(memory, &ctx, target_address)?;
let target_function = read_string(memory, &ctx, target_function)?;
let params = read_buffer(memory, &ctx, params)?;
let response = env.get_interface().deferred_call_register(
&target_address,
&target_function,
asc_target_slot,
max_gas as u64,
raw_coins as u64,
&params,
)?;
let res = match BufferPtr::alloc(&response, env.get_ffi_env(), &mut ctx) {
Ok(ret) => Ok(ret.offset() as i32),
_ => abi_bail!("Cannot allocate response in asc call register"),
};
#[cfg(feature = "execution-trace")]
ctx.data_mut().trace.push(AbiTrace {
name: function_name!().to_string(),
params: vec![
into_trace_value!(target_address),
into_trace_value!(target_function),
into_trace_value!(target_period),
into_trace_value!(target_thread),
into_trace_value!(max_gas as u64),
into_trace_value!(raw_coins as u64),
into_trace_value!(params),
],
return_value: response.to_owned().into(),
sub_calls: None,
});
res
}

/// Check if an deferred call exists with the given deferred_call_id (exists meaning to be executed in the future).
#[named]
pub(crate) fn assembly_script_deferred_call_exists(
mut ctx: FunctionEnvMut<ASEnv>,
deferred_id: i32,
) -> ABIResult<i32> {
let env = get_env(&ctx)?;
sub_remaining_gas_abi(&env, &mut ctx, function_name!())?;
let memory = get_memory!(env);
let asc_id = read_buffer(memory, &ctx, deferred_id)?;
let exists = env.get_interface().deferred_call_exists(&asc_id)?;
#[cfg(feature = "execution-trace")]
ctx.data_mut().trace.push(AbiTrace {
name: function_name!().to_string(),
params: vec![into_trace_value!(asc_id)],
return_value: exists.into(),
sub_calls: None,
});
Ok(exists as i32)
}

/// Cancel an deferred call with the given deferred_call_id. This will reimburse the user with the coins they provided
#[named]
pub(crate) fn assembly_script_deferred_call_cancel(
mut ctx: FunctionEnvMut<ASEnv>,
deferred_call_id: i32,
) -> ABIResult<()> {
let env = get_env(&ctx)?;
sub_remaining_gas_abi(&env, &mut ctx, function_name!())?;
let memory = get_memory!(env);
let deferred_id = read_buffer(memory, &ctx, deferred_call_id)?;
env.get_interface().deferred_call_cancel(&deferred_id)?;
#[cfg(feature = "execution-trace")]
ctx.data_mut().trace.push(AbiTrace {
name: function_name!().to_string(),
params: vec![into_trace_value!(deferred_id)],
return_value: (),
sub_calls: None,
});
Ok(())
}

/// Assembly script builtin `abort` function.
///
/// It prints the origin filename, an error messag, the line and column.
Expand Down
4 changes: 4 additions & 0 deletions src/as_execution/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ impl ASContext {
"assembly_script_caller_has_write_access" => Function::new_typed_with_env(store, &fenv, assembly_script_caller_has_write_access),
"assembly_script_function_exists" => Function::new_typed_with_env(store, &fenv, assembly_script_function_exists),
"assembly_script_chain_id" => Function::new_typed_with_env(store, &fenv, assembly_script_chain_id),
"assembly_script_get_deferred_call_quote" => Function::new_typed_with_env(store, &fenv, assembly_script_get_deferred_call_quote),
"assembly_script_deferred_call_register" => Function::new_typed_with_env(store, &fenv, assembly_script_deferred_call_register),
"assembly_script_deferred_call_exists" => Function::new_typed_with_env(store, &fenv, assembly_script_deferred_call_exists),
"assembly_script_deferred_call_cancel" => Function::new_typed_with_env(store, &fenv, assembly_script_deferred_call_cancel),
},
};

Expand Down
34 changes: 34 additions & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,40 @@ impl Interface for TestInterface {
fn save_gas_remaining_before_subexecution(&self, gas_used_until: u64) {
println!("save_gas_remaining_before_subexecution: {}", gas_used_until);
}

fn deferred_call_quote(&self, target_slot: (u64, u8), gas_limit: u64) -> Result<(bool, u64)> {
println!(
"get_asc_call_fee: target_slot: {:?}, gas_limit: {}",
target_slot, gas_limit
);
Ok((true, 0))
}

fn deferred_call_register(
&self,
target_slot: (u64, u8),
target_addr: &str,
target_func: &str,
params: &[u8],
coins: u64,
max_gas: u64,
) -> Result<Vec<u8>> {
modship marked this conversation as resolved.
Show resolved Hide resolved
println!(
"asc_call_register: target_slot: {:?}, target_addr: {}, target_func: {}, params: {:?}, coins: {}, max_gas: {}",
target_slot, target_addr, target_func, params, coins, max_gas
);
Ok(vec![])
}

fn deferred_call_exists(&self, id: &[u8]) -> Result<bool> {
println!("asc_call_exists: id: {:?}", id);
Ok(true)
}

fn deferred_call_cancel(&self, id: &[u8]) -> Result<()> {
println!("asc_call_cancel: id: {:?}", id);
Ok(())
}
}

#[cfg(feature = "gas_calibration")]
Expand Down
24 changes: 24 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,10 @@ impl Default for GasCosts {
abi_costs.insert(String::from("assembly_script_get_bytecode_for"), 11);
abi_costs.insert(String::from("assembly_script_caller_has_write_access"), 11);
abi_costs.insert(String::from("assembly_script_function_exists"), 11);
abi_costs.insert(String::from("assembly_script_get_deferred_call_quote"), 11);
abi_costs.insert(String::from("assembly_script_deferred_call_register"), 11);
abi_costs.insert(String::from("assembly_script_deferred_call_exists"), 11);
abi_costs.insert(String::from("assembly_script_deferred_call_cancel"), 11);
Comment on lines +274 to +277
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO calibrate

abi_costs.insert(String::from("assembly_script_seed"), 11);
abi_costs.insert(String::from("assembly_script_abort"), 11);
abi_costs.insert(String::from("assembly_script_date_now"), 11);
Expand Down Expand Up @@ -573,6 +577,26 @@ pub trait Interface: Send + Sync + InterfaceClone {
// Return the current chain id
fn chain_id(&self) -> Result<u64>;

// Return a boolean that determine if there is place in this slot and an amount of fee needed to take the space
fn deferred_call_quote(&self, target_slot: (u64, u8), gas_limit: u64) -> Result<(bool, u64)>;

// Register a new deferred call and return his id
fn deferred_call_register(
&self,
target_addr: &str,
target_func: &str,
target_slot: (u64, u8),
max_gas: u64,
coins: u64,
params: &[u8],
) -> Result<Vec<u8>>;

// Return true if the current deferred call exists
fn deferred_call_exists(&self, id: &[u8]) -> Result<bool>;

// Cancel a deferred call (will return the coins)
fn deferred_call_cancel(&self, id: &[u8]) -> Result<()>;

fn native_amount_from_str_wasmv1(&self, amount: &str) -> Result<NativeAmount>;

fn native_amount_to_string_wasmv1(&self, amount: &NativeAmount) -> Result<String>;
Expand Down
Loading