Skip to content

feat: have contract call compute the right cost call#7164

Open
melcar-stacks wants to merge 1 commit into
stacks-network:feat/clarity-wasm-developfrom
melcar-stacks:feat/cost_computing_works_with_contract_calls
Open

feat: have contract call compute the right cost call#7164
melcar-stacks wants to merge 1 commit into
stacks-network:feat/clarity-wasm-developfrom
melcar-stacks:feat/cost_computing_works_with_contract_calls

Conversation

@melcar-stacks

@melcar-stacks melcar-stacks commented Apr 22, 2026

Copy link
Copy Markdown

Add changes for 798 in clarity. All context for these changes can be found in that PR

to charge the right cost, we needed the ability to pass from and to
caller/callee the cost before and after call.
@melcar-stacks melcar-stacks marked this pull request as ready for review April 22, 2026 10:58
@melcar-stacks melcar-stacks requested a review from a team as a code owner April 22, 2026 10:58

let in_mem_offset = offset + arg_size;

ensure_memory(&memory, &mut store.as_context_mut(), in_mem_offset as usize)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

That would create a second usage of this function for each contract call. This could be costly. It's highly unlikely but we could have to recreate a new memory twice (we would need to call a function where the arguments size are bigger than a wasm page), but it's a possibility.

Comment on lines +493 to +507
// Access the global stack pointer from the instance
let stack_pointer = instance
.get_global(&mut store.as_context_mut(), "stack-pointer")
.ok_or(Error::Wasm(WasmError::GlobalNotFound(
"stack-pointer".to_string(),
)))?;

let offset = stack_pointer
.get(&mut store.as_context_mut())
.i32()
.ok_or(Error::Wasm(WasmError::ValueTypeMismatch))?;

let memory = instance
.get_memory(&mut store.as_context_mut(), "memory")
.ok_or(Error::Wasm(WasmError::MemoryNotFound))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

call_function will also compute all these. Pass them as parameter instead of recomputing them.

number_of_arguments: u32,
total_size_of_parameters: u32,
) -> Result<(), Error> {
let function_name = ".contract-call-cost-overhead";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pfffffffff... at worst, that's a constant, but this let is a bit excessive....

// Charge the cost of contract call analog to the UserFunctionApplication and InnerTypeCheckCost in the interpreter.
// UserFunctionApplication charge proportionally to the number of arguments passed to the contract call.
// InnerTypeCheckCost charge proportionally to the cumulative size of each argument's type.
fn apply_contract_call_cost(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

What is even the point of this function? It's recomputing most of the stuffs we already have in call_function, and then it calls the wasm function .contract-call-cost-overhead. Why not inline it and merge some operations (the lookup for memory and stack pointer, the ensure_memory call, the update of stack-pointer).

name: &str,
value: Val,
) -> Result<Global, Error> {
let store2 = store.as_context_mut();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

store2? Where is store1?

)
.map_err(|e| Error::Wasm(WasmError::UnableToLoadModule(e)))?;

let mut store2 = store.as_context_mut();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

huh?

value: Val,
) -> Result<Global, Error> {
let store2 = store.as_context_mut();
let the_global = Global::new(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

the name is the awesome.

Comment on lines +2267 to +2276
let runtime = link_global(linker, store, Cost::Runtime.as_str(), Val::I64(i64::MAX))?;
let read_count = link_global(linker, store, Cost::ReadCount.as_str(), Val::I64(i64::MAX))?;
let read_length = link_global(linker, store, Cost::ReadLength.as_str(), Val::I64(i64::MAX))?;
let write_count = link_global(linker, store, Cost::WriteCount.as_str(), Val::I64(i64::MAX))?;
let write_length = link_global(
linker,
store,
Cost::WriteLength.as_str(),
Val::I64(i64::MAX),
)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

All those i64::MAX are the initial value for all these costs? And they aren't defined anywhere as constants? 😮

@CLAassistant

CLAassistant commented May 20, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants