Skip to content
Open
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
34 changes: 22 additions & 12 deletions clarity/src/vm/functions/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,28 @@ pub fn special_contract_call(
} else {
let trait_name = trait_identifier.name.to_string();

// Retrieve, from the trait definition, the expected method signature
let contract_defining_trait = env
.global_context
.database
.get_contract(&trait_identifier.contract_identifier)
.map_err(|_e| {
RuntimeCheckErrorKind::NoSuchContract(
trait_identifier.contract_identifier.to_string(),
)
})?;
let contract_context_defining_trait =
contract_defining_trait.contract_context;
// Retrieve, from the trait definition, the expected method signature.
// Check if the trait is defined in the contract context (Clarity >= 5).
let contract_context_defining_trait = if env
.contract_context
.get_clarity_version()
.allows_local_trait_lookup()
&& trait_identifier.contract_identifier
== env.contract_context.contract_identifier
{
env.contract_context.clone()
} else {
let contract_defining_trait = env
.global_context
.database
.get_contract(&trait_identifier.contract_identifier)
.map_err(|_e| {
RuntimeCheckErrorKind::NoSuchContract(
trait_identifier.contract_identifier.to_string(),
)
})?;
contract_defining_trait.contract_context
};

// Retrieve the function that will be invoked
let function_to_check = contract_context_to_check
Expand Down
39 changes: 39 additions & 0 deletions clarity/src/vm/tests/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2071,3 +2071,42 @@ fn test_pass_principal_literal_to_trait(
);
}
}

#[apply(test_clarity_versions)]
fn test_trait_use_at_top_level_same_contract(
version: ClarityVersion,
epoch: StacksEpochId,
mut env_factory: MemoryEnvironmentGenerator,
) {
let mut owned_env = env_factory.get_env(epoch);

let contract_foo = "(define-public (foo) (ok true))";

let contract_bar = "(define-trait trait-1 (
(foo () (response bool uint))))
(define-private (bar (F <trait-1>))
(unwrap-panic (contract-call? F foo)))
(bar .c-foo)";

let placeholder_context =
ContractContext::new(QualifiedContractIdentifier::transient(), version);
let mut env = owned_env.get_exec_environment(None, None, &placeholder_context);

env.initialize_contract(
QualifiedContractIdentifier::local("c-foo").unwrap(),
contract_foo,
)
.unwrap();

let contract_init_result = env.initialize_contract(
QualifiedContractIdentifier::local("c-bar").unwrap(),
contract_bar,
);

if version.allows_local_trait_lookup() {
contract_init_result.expect("should initialize successfully");
} else {
contract_init_result
.expect_err("should fail in Clarity versions without local trait lookup");
}
}
10 changes: 10 additions & 0 deletions clarity/src/vm/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ impl ClarityVersion {
ClarityVersion::Clarity5,
];

pub fn allows_local_trait_lookup(&self) -> bool {
match self {
ClarityVersion::Clarity1
| ClarityVersion::Clarity2
| ClarityVersion::Clarity3
| ClarityVersion::Clarity4 => false,
ClarityVersion::Clarity5 => true,
}
}

pub fn default_for_epoch(epoch_id: StacksEpochId) -> ClarityVersion {
match epoch_id {
StacksEpochId::Epoch10 => {
Expand Down