Skip to content

Commit 2c59e26

Browse files
committed
fix: contract-call? linked function will now parse a TraitIdentifier for the trait
1 parent 5295a70 commit 2c59e26

File tree

1 file changed

+60
-19
lines changed

1 file changed

+60
-19
lines changed

clarity/src/vm/clarity_wasm.rs

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6451,8 +6451,8 @@ fn link_contract_call_fn(linker: &mut Linker<ClarityWasmContext>) -> Result<(),
64516451
"clarity",
64526452
"contract_call",
64536453
|mut caller: Caller<'_, ClarityWasmContext>,
6454-
trait_name_offset: i32,
6455-
trait_name_length: i32,
6454+
trait_id_offset: i32,
6455+
trait_id_length: i32,
64566456
contract_offset: i32,
64576457
contract_length: i32,
64586458
function_offset: i32,
@@ -6499,7 +6499,7 @@ fn link_contract_call_fn(linker: &mut Linker<ClarityWasmContext>) -> Result<(),
64996499
)?;
65006500

65016501
// Retrieve the contract context for the contract we're calling
6502-
let contract = caller
6502+
let mut contract = caller
65036503
.data_mut()
65046504
.global_context
65056505
.database
@@ -6568,30 +6568,34 @@ fn link_contract_call_fn(linker: &mut Linker<ClarityWasmContext>) -> Result<(),
65686568
}?;
65696569

65706570
// Write the result to the return buffer
6571-
let return_ty = if trait_name_length == 0 {
6571+
let return_ty = if trait_id_length == 0 {
65726572
// This is a direct call
6573-
function.get_return_type().as_ref()
6573+
function
6574+
.get_return_type()
6575+
.as_ref()
6576+
.ok_or(CheckErrors::DefineFunctionBadSignature)?
65746577
} else {
65756578
// This is a dynamic call
6576-
let trait_name = read_identifier_from_wasm(
6577-
memory,
6578-
&mut caller,
6579-
trait_name_offset,
6580-
trait_name_length,
6581-
)?;
6579+
let trait_id =
6580+
read_bytes_from_wasm(memory, &mut caller, trait_id_offset, trait_id_length)
6581+
.and_then(|bs| trait_identifier_from_bytes(&bs))?;
6582+
contract = if &trait_id.contract_identifier == contract_id {
6583+
contract
6584+
} else {
6585+
caller
6586+
.data_mut()
6587+
.global_context
6588+
.database
6589+
.get_contract(&trait_id.contract_identifier)?
6590+
};
65826591
contract
65836592
.contract_context
65846593
.defined_traits
6585-
.get(trait_name.as_str())
6594+
.get(trait_id.name.as_str())
65866595
.and_then(|trait_functions| trait_functions.get(function_name.as_str()))
65876596
.map(|f_ty| &f_ty.returns)
6588-
}
6589-
.ok_or(CheckErrors::DefineFunctionBadSignature)?;
6590-
6591-
let memory = caller
6592-
.get_export("memory")
6593-
.and_then(|export| export.into_memory())
6594-
.ok_or(Error::Wasm(WasmError::MemoryNotFound))?;
6597+
.ok_or(CheckErrors::DefineFunctionBadSignature)?
6598+
};
65956599

65966600
write_to_wasm(
65976601
&mut caller,
@@ -7376,6 +7380,43 @@ fn link_debug_msg<T>(linker: &mut Linker<T>) -> Result<(), Error> {
73767380
})
73777381
}
73787382

7383+
/// Tries to deserialize bytes into a [TraitIdentifier]. The bytes should have the following format:
7384+
/// issuer principal as 21 bytes + contract name length as byte + contract name as bytes + trait name length as byte + trait name as bytes
7385+
///
7386+
/// This is a duplication of the function defined in clarity-wasm due to the duplication issue.
7387+
pub fn trait_identifier_from_bytes(bytes: &[u8]) -> Result<TraitIdentifier, Error> {
7388+
let not_enough_bytes = || {
7389+
Error::Wasm(WasmError::Expect(
7390+
"Not enough bytes for a trait deserialization".to_owned(),
7391+
))
7392+
};
7393+
7394+
// deserilize issuer
7395+
let (version, bytes) = bytes.split_first().ok_or_else(not_enough_bytes)?;
7396+
let (issuer_bytes, bytes) = bytes.split_at_checked(20).ok_or_else(not_enough_bytes)?;
7397+
let issuer = StandardPrincipalData::new(*version, issuer_bytes.try_into().unwrap())?;
7398+
7399+
// deserialize contract name
7400+
let (contract_name_len, bytes) = bytes.split_first().ok_or_else(not_enough_bytes)?;
7401+
let (contract_name_bytes, bytes) = bytes
7402+
.split_at_checked(*contract_name_len as usize)
7403+
.ok_or_else(not_enough_bytes)?;
7404+
let contract_name: ContractName = String::from_utf8(contract_name_bytes.to_owned())
7405+
.map_err(|err| Error::Wasm(WasmError::UnableToReadIdentifier(err)))?
7406+
.try_into()?;
7407+
7408+
// deserialize trait name
7409+
let (trait_name_len, bytes) = bytes.split_first().ok_or_else(not_enough_bytes)?;
7410+
if bytes.len() != *trait_name_len as usize {
7411+
return Err(not_enough_bytes());
7412+
}
7413+
let trait_name: ClarityName = String::from_utf8(bytes.to_owned())
7414+
.map_err(|err| Error::Wasm(WasmError::UnableToReadIdentifier(err)))?
7415+
.try_into()?;
7416+
7417+
Ok(TraitIdentifier::new(issuer, contract_name, trait_name))
7418+
}
7419+
73797420
#[cfg(test)]
73807421
mod tests {
73817422
use wasmtime::*;

0 commit comments

Comments
 (0)