Skip to content

Commit d48d8ac

Browse files
committed
fix: apply review comments
removed function call, to inline it instead and reuse computed values. + general cleanup
1 parent 7e532eb commit d48d8ac

1 file changed

Lines changed: 53 additions & 99 deletions

File tree

clarity/src/vm/clarity_wasm.rs

Lines changed: 53 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use std::fmt::{self, Display};
22
use std::io::{Cursor, Write as _};
33
use std::ops::{AddAssign, SubAssign};
44

5-
use crate::vm::ExecutionCost;
65
use stacks_common::types::StacksEpochId;
76
use stacks_common::types::chainstate::StacksBlockId;
87
use stacks_common::util::hash::{Keccak256Hash, Sha512Sum, Sha512Trunc256Sum};
@@ -32,7 +31,7 @@ use crate::vm::errors::{RuntimeCheckErrorKind, RuntimeError, VmExecutionError, W
3231
use crate::vm::types::{
3332
BufferLength, SequenceSubtype, SequencedValue, StringSubtype, TypeSignature, TypeSignatureExt,
3433
};
35-
use crate::vm::{ClarityName, ContractContext, CostErrors, Value};
34+
use crate::vm::{ClarityName, ContractContext, CostErrors, ExecutionCost, Value};
3635

3736
enum MintAssetErrorCodes {
3837
ALREADY_EXIST = 1,
@@ -473,75 +472,6 @@ pub fn initialize_contract(
473472
}
474473
}
475474

476-
// Charge the cost of contract call analog to the UserFunctionApplication and InnerTypeCheckCost in the interpreter.
477-
// UserFunctionApplication charge proportionally to the number of arguments passed to the contract call.
478-
// InnerTypeCheckCost charge proportionally to the cumulative size of each argument's type.
479-
fn apply_contract_call_cost(
480-
instance: &Instance,
481-
store: &mut impl AsContextMut,
482-
contract_context: &ContractContext,
483-
epoch_id: &StacksEpochId,
484-
number_of_arguments: u32,
485-
total_size_of_parameters: u32,
486-
) -> Result<(), VmExecutionError> {
487-
let function_name = ".contract-call-cost-overhead";
488-
let func = instance
489-
.get_func(&mut store.as_context_mut(), function_name)
490-
.ok_or(RuntimeCheckErrorKind::UndefinedFunction(
491-
function_name.into(),
492-
))?;
493-
494-
// Access the global stack pointer from the instance
495-
let stack_pointer = instance
496-
.get_global(&mut store.as_context_mut(), "stack-pointer")
497-
.ok_or(VmExecutionError::Wasm(WasmError::GlobalNotFound(
498-
"stack-pointer".to_string(),
499-
)))?;
500-
501-
let offset = stack_pointer
502-
.get(&mut store.as_context_mut())
503-
.i32()
504-
.ok_or(VmExecutionError::Wasm(WasmError::ValueTypeMismatch))?;
505-
506-
let memory = instance
507-
.get_memory(&mut store.as_context_mut(), "memory")
508-
.ok_or(VmExecutionError::Wasm(WasmError::MemoryNotFound))?;
509-
510-
// Determine how much space is needed for arguments
511-
//4 byte for an i32
512-
let arg_size = 2 * 4;
513-
514-
let in_mem_offset = offset + arg_size;
515-
516-
ensure_memory(&memory, &mut store.as_context_mut(), in_mem_offset as usize)?;
517-
518-
// Convert the args into wasmtime values
519-
let wasm_args = vec![
520-
Val::I32(number_of_arguments as i32),
521-
Val::I32(total_size_of_parameters as i32),
522-
];
523-
524-
// Update the stack pointer after space is reserved for the arguments and
525-
// return values.
526-
stack_pointer
527-
.set(&mut store.as_context_mut(), Val::I32(offset))
528-
.map_err(|e| VmExecutionError::Wasm(WasmError::Runtime(e)))?;
529-
530-
// Call the function
531-
func.call(&mut store.as_context_mut(), &wasm_args, &mut [])
532-
.map_err(|e| {
533-
error_mapping::resolve_error(
534-
e,
535-
*instance,
536-
&mut store.as_context_mut(),
537-
epoch_id,
538-
contract_context.get_clarity_version(),
539-
)
540-
})?;
541-
542-
Ok(())
543-
}
544-
545475
/// Call a function in the contract.
546476
#[allow(clippy::too_many_arguments)]
547477
pub fn call_function<'a>(
@@ -600,25 +530,6 @@ pub fn call_function<'a>(
600530
.instantiate(&mut store, &module)
601531
.map_err(|e| VmExecutionError::Wasm(WasmError::UnableToLoadModule(e)))?;
602532

603-
let mut total_size = 0;
604-
for arg in func_types.get_arg_types() {
605-
total_size += arg.size()?;
606-
}
607-
608-
apply_contract_call_cost(
609-
&instance,
610-
&mut store.as_context_mut(),
611-
contract_context,
612-
&epoch,
613-
args.len() as u32,
614-
total_size,
615-
)?;
616-
617-
// Call the specified function
618-
let func = instance.get_func(&mut store, function_name).ok_or(
619-
RuntimeCheckErrorKind::UndefinedFunction(function_name.to_string()),
620-
)?;
621-
622533
// Access the global stack pointer from the instance
623534
let stack_pointer =
624535
instance
@@ -641,12 +552,6 @@ pub fn call_function<'a>(
641552
.get_memory(&mut store, "memory")
642553
.ok_or(VmExecutionError::Wasm(WasmError::MemoryNotFound))?;
643554

644-
let return_type = func_types
645-
.get_return_type()
646-
.as_ref()
647-
.ok_or(VmExecutionError::Wasm(WasmError::ExpectedReturnValue))?
648-
.clone();
649-
650555
// Validate argument count
651556
let expected_args = func_types.get_arg_types();
652557
if args.len() != expected_args.len() {
@@ -677,8 +582,51 @@ pub fn call_function<'a>(
677582
total_required_bytes += get_required_bytes(ty, arg)?;
678583
}
679584

585+
// Space needed for the arguments to call the overhead cost for contract call
586+
//4 byte for an i32
587+
let total_required_bytes_contract_call = 8;
588+
589+
total_required_bytes = total_required_bytes.max(total_required_bytes_contract_call);
590+
680591
ensure_memory(&memory, &mut store, total_required_bytes + offset as usize)?;
681592

593+
// Before calling the function, we need to check if we have enough fuel to do so
594+
// Apply contract call cost
595+
let mut total_size_of_parameters = 0;
596+
for arg in func_types.get_arg_types() {
597+
total_size_of_parameters += arg.size()?;
598+
}
599+
// Convert the args into wasmtime values
600+
let wasm_args = vec![
601+
Val::I32(args.len() as i32),
602+
Val::I32(total_size_of_parameters as i32),
603+
];
604+
605+
let contract_call_cost_func = instance
606+
.get_func(&mut store.as_context_mut(), ".contract-call-cost-overhead")
607+
.ok_or(RuntimeCheckErrorKind::UndefinedFunction(
608+
".contract-call-cost-overhead".into(),
609+
))?;
610+
611+
// Compute and spend contract call cost
612+
contract_call_cost_func
613+
.call(&mut store.as_context_mut(), &wasm_args, &mut [])
614+
.map_err(|e| {
615+
error_mapping::resolve_error(
616+
e,
617+
instance,
618+
&mut store.as_context_mut(),
619+
&epoch,
620+
contract_context.get_clarity_version(),
621+
)
622+
})?;
623+
624+
// Now that we checked if we had enough fuel to make the contract call
625+
// We call the specified function
626+
let func = instance.get_func(&mut store, function_name).ok_or(
627+
RuntimeCheckErrorKind::UndefinedFunction(function_name.to_string()),
628+
)?;
629+
682630
// Convert the args into wasmtime values
683631
let mut wasm_args = vec![];
684632
for (arg, ty) in args.iter().zip(expected_args) {
@@ -693,6 +641,12 @@ pub fn call_function<'a>(
693641
.set(&mut store, Val::I32(offset))
694642
.map_err(|e| VmExecutionError::Wasm(WasmError::Runtime(e)))?;
695643

644+
let return_type = func_types
645+
.get_return_type()
646+
.as_ref()
647+
.ok_or(VmExecutionError::Wasm(WasmError::ExpectedReturnValue))?
648+
.clone();
649+
696650
// Call the function
697651
let mut results: Vec<_> = clar2wasm_ty(&return_type)
698652
.into_iter()
@@ -2306,17 +2260,17 @@ fn link_global<T>(
23062260
name: &str,
23072261
value: Val,
23082262
) -> Result<Global, VmExecutionError> {
2309-
let the_global = Global::new(
2263+
let global_to_link = Global::new(
23102264
store.as_context_mut(),
23112265
GlobalType::new(wasmtime::ValType::I64, wasmtime::Mutability::Var),
23122266
value,
23132267
)
23142268
.map_err(|e| VmExecutionError::Wasm(WasmError::UnableToLoadModule(e)))?;
23152269

23162270
linker
2317-
.define(&mut store.as_context_mut(), "clarity", name, the_global)
2271+
.define(&mut store.as_context_mut(), "clarity", name, global_to_link)
23182272
.map_err(|e| VmExecutionError::Wasm(WasmError::UnableToLoadModule(e)))?;
2319-
Ok(the_global)
2273+
Ok(global_to_link)
23202274
}
23212275

23222276
/// Link the host interface functions for into the Wasm module.

0 commit comments

Comments
 (0)