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

Feat/explicit-contract-version #3192

Merged
merged 51 commits into from
Aug 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
90df630
feat: add the ability to get the clarity version of an analyzed contract
jcnelson Jul 6, 2022
e8daea3
feat: add the ability to get the clarity version of a clarity connect…
jcnelson Jul 6, 2022
fc477b0
feat: use the clarity version in the contract context to deduce which…
jcnelson Jul 6, 2022
59983d4
chore: API sync
jcnelson Jul 6, 2022
82eb521
feat: gate the explicit-versioned smart contract transaction variant …
jcnelson Jul 6, 2022
39b068c
chore: API sync
jcnelson Jul 6, 2022
d431162
chore: API sync
jcnelson Jul 6, 2022
728f294
feat: reject transactions from the mempool if they aren't compatible …
jcnelson Jul 6, 2022
19f0245
chore: API sync (and also cargo fmt, which contributes the vast, vast…
jcnelson Jul 6, 2022
a9578f3
feat: when processing a transaction that either deploys a smart contr…
jcnelson Jul 6, 2022
b062dfb
chore: API sync
jcnelson Jul 6, 2022
fe7fe36
feat: TransactionPayload::SmartContract takes an optional clarity ver…
jcnelson Jul 6, 2022
625841d
chore: API sync
jcnelson Jul 6, 2022
dcd8c2d
feat: functional test to verify that smart contracts and contract-cal…
jcnelson Jul 6, 2022
ba72478
feat: new test infrastructure for versioned smart contracts and custo…
jcnelson Jul 6, 2022
9880cd5
feat: versioned smart contract transaction codec
jcnelson Jul 6, 2022
a564173
chore: API sync
jcnelson Jul 6, 2022
461c474
feat: when starting transaction-processing, require a clarity version…
jcnelson Jul 6, 2022
7f45647
chore: API sync, and testing with different epochs and clarity versions
jcnelson Jul 6, 2022
af5db2a
chore: API sync
jcnelson Jul 6, 2022
5762fae
feat: test coverage for mempool gating for 2.1 contracts, and functio…
jcnelson Jul 6, 2022
7688c3d
chore: API sync
jcnelson Jul 6, 2022
bfc7678
chore: API sync
jcnelson Jul 6, 2022
cfa94ef
Merge branch 'next' into feat/smart-contract-v2
jcnelson Jul 6, 2022
94ed516
feat: test at-block across clarity versions
jcnelson Jul 7, 2022
ae88b4c
feat: test contract-calls to trait implementations between contracts …
jcnelson Jul 7, 2022
7e58726
fix: repair broken unit tests so that they use clarity2 only when in …
jcnelson Jul 8, 2022
8763c5d
Merge branch 'next' into feat/smart-contract-v2
jcnelson Jul 21, 2022
898f66f
refactor: OwnedEnvironment is oblivious to clarity version
jcnelson Jul 22, 2022
b673063
refactor: remove default_contract from OwnedEnvironment, and make it …
jcnelson Jul 22, 2022
4be1eb2
refactor: sync tests to new APIs
jcnelson Jul 22, 2022
a882002
refactor: as_transaction() and start_transaction_processing() no long…
jcnelson Jul 22, 2022
5aeced7
refactor: API sync
jcnelson Jul 22, 2022
7371a1e
fix: no need to check the smart contract version of a contract-call t…
jcnelson Jul 22, 2022
dad3c9f
refactor: don't pass clarity version to .as_transaction()
jcnelson Jul 22, 2022
1c07a55
refactor: don't pass clarity version to .as_transaction()
jcnelson Jul 22, 2022
04b37e2
refactor: API sync in tests
jcnelson Jul 22, 2022
39687ca
refactor: .as_transaction() does not take a clarity version
jcnelson Jul 22, 2022
410ed90
refactor: API sync
jcnelson Jul 22, 2022
f532798
fix: use correct network epoch ID in test
jcnelson Jul 22, 2022
644b10c
chore: prefix unused analysis variables with _
jcnelson Jul 22, 2022
6d87ac1
chore: API sync documentation
jcnelson Jul 22, 2022
b026a22
feat: remove OwnedEnvironment::initialize_contract() and make it test…
jcnelson Jul 22, 2022
f52a0b6
chore: remove gratuitous debug output
jcnelson Jul 22, 2022
37f2942
chore: API sync
jcnelson Jul 22, 2022
521772f
chore: API sync
jcnelson Jul 22, 2022
7116f46
chore: API sync
jcnelson Jul 22, 2022
186ee50
chore: update costs tests to use an explicit clarity version
jcnelson Jul 22, 2022
ef4ef0c
fix: API sync
jcnelson Jul 22, 2022
789b620
fix: use epoch-specific clarity version
jcnelson Jul 22, 2022
07843cd
fix: explicitly set CARGO_MANIFEST_DIR in a bid to fix CI
jcnelson Jul 29, 2022
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
2 changes: 2 additions & 0 deletions .github/actions/bitcoin-int-tests/Dockerfile.code-cov
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ FROM rust:bullseye AS test

WORKDIR /build

ENV CARGO_MANIFEST_DIR="$(pwd)"

RUN rustup override set nightly-2022-01-14 && \
rustup component add llvm-tools-preview && \
cargo install grcov
Expand Down
16 changes: 16 additions & 0 deletions clarity/src/vm/analysis/analysis_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ use crate::vm::representations::ClarityName;
use crate::vm::types::signatures::FunctionSignature;
use crate::vm::types::{FunctionType, QualifiedContractIdentifier, TraitIdentifier, TypeSignature};

use crate::vm::ClarityVersion;

pub struct AnalysisDatabase<'a> {
store: RollbackWrapper<'a>,
}
Expand Down Expand Up @@ -110,6 +112,20 @@ impl<'a> AnalysisDatabase<'a> {
Ok(())
}

pub fn get_clarity_version(
&mut self,
contract_identifier: &QualifiedContractIdentifier,
) -> CheckResult<ClarityVersion> {
// TODO: this function loads the whole contract to obtain the function type.
// but it doesn't need to -- rather this information can just be
// stored as its own entry. the analysis cost tracking currently only
// charges based on the function type size.
let contract = self
.load_contract(contract_identifier)
.ok_or(CheckErrors::NoSuchContract(contract_identifier.to_string()))?;
Ok(contract.clarity_version)
}

pub fn get_public_function_type(
&mut self,
contract_identifier: &QualifiedContractIdentifier,
Expand Down
12 changes: 8 additions & 4 deletions clarity/src/vm/clarity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::vm::errors::Error as InterpreterError;
use crate::vm::events::StacksTransactionEvent;
use crate::vm::types::{BuffData, PrincipalData, QualifiedContractIdentifier};
use crate::vm::ClarityVersion;
use crate::vm::ContractContext;
use crate::vm::{ast, SymbolicExpression, Value};
use stacks_common::types::StacksEpochId;
use std::fmt;
Expand Down Expand Up @@ -120,6 +121,7 @@ pub trait ClarityConnection {
&mut self,
mainnet: bool,
chain_id: u32,
clarity_version: ClarityVersion,
sender: PrincipalData,
sponsor: Option<PrincipalData>,
cost_track: LimitedCostTracker,
Expand All @@ -130,11 +132,13 @@ pub trait ClarityConnection {
{
let epoch_id = self.get_epoch();
self.with_clarity_db_readonly_owned(|clarity_db| {
let initial_context =
ContractContext::new(QualifiedContractIdentifier::transient(), clarity_version);
let mut vm_env = OwnedEnvironment::new_cost_limited(
mainnet, chain_id, clarity_db, cost_track, epoch_id,
);
let result = vm_env
.execute_in_env(sender, sponsor, to_do)
.execute_in_env(sender, sponsor, Some(initial_context), to_do)
.map(|(result, _, _)| result);
let (db, _) = vm_env
.destruct()
Expand Down Expand Up @@ -167,13 +171,11 @@ pub trait TransactionConnection: ClarityConnection {
fn analyze_smart_contract(
&mut self,
identifier: &QualifiedContractIdentifier,
clarity_version: ClarityVersion,
contract_content: &str,
) -> Result<(ContractAST, ContractAnalysis), Error> {
let epoch_id = self.get_epoch();

// ClarityVersionPragmaTodo: need to use contract's declared version or default
let clarity_version = ClarityVersion::default_for_epoch(epoch_id);

self.with_analysis_db(|db, mut cost_track| {
let ast_result = ast::build_ast(
identifier,
Expand Down Expand Up @@ -304,6 +306,7 @@ pub trait TransactionConnection: ClarityConnection {
fn initialize_smart_contract<F>(
&mut self,
identifier: &QualifiedContractIdentifier,
clarity_version: ClarityVersion,
contract_ast: &ContractAST,
contract_str: &str,
sponsor: Option<PrincipalData>,
Expand All @@ -317,6 +320,7 @@ pub trait TransactionConnection: ClarityConnection {
vm_env
.initialize_contract_from_ast(
identifier.clone(),
clarity_version,
contract_ast,
contract_str,
sponsor,
Expand Down
117 changes: 69 additions & 48 deletions clarity/src/vm/contexts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ pub struct Environment<'a, 'b> {

pub struct OwnedEnvironment<'a> {
context: GlobalContext<'a>,
default_contract: ContractContext,
call_stack: CallStack,
}

Expand Down Expand Up @@ -553,10 +552,6 @@ impl<'a> OwnedEnvironment<'a> {
LimitedCostTracker::new_free(),
StacksEpochId::Epoch2_05,
),
default_contract: ContractContext::new(
QualifiedContractIdentifier::transient(),
ClarityVersion::Clarity1,
),
call_stack: CallStack::new(),
}
}
Expand All @@ -580,10 +575,6 @@ impl<'a> OwnedEnvironment<'a> {
LimitedCostTracker::new_free(),
epoch,
),
default_contract: ContractContext::new(
QualifiedContractIdentifier::transient(),
version,
),
call_stack: CallStack::new(),
}
}
Expand All @@ -595,17 +586,12 @@ impl<'a> OwnedEnvironment<'a> {
use_mainnet: bool,
) -> OwnedEnvironment<'a> {
use crate::vm::tests::test_only_mainnet_to_chain_id;
let version = ClarityVersion::default_for_epoch(epoch);
let cost_track = LimitedCostTracker::new_max_limit(&mut database, epoch, use_mainnet)
.expect("FAIL: problem instantiating cost tracking");
let chain_id = test_only_mainnet_to_chain_id(use_mainnet);

OwnedEnvironment {
context: GlobalContext::new(use_mainnet, chain_id, database, cost_track, epoch),
default_contract: ContractContext::new(
QualifiedContractIdentifier::transient(),
version,
),
call_stack: CallStack::new(),
}
}
Expand All @@ -624,7 +610,6 @@ impl<'a> OwnedEnvironment<'a> {
database: ClarityDatabase<'a>,
epoch_id: StacksEpochId,
) -> OwnedEnvironment<'a> {
let version = ClarityVersion::default_for_epoch(epoch_id);
OwnedEnvironment {
context: GlobalContext::new(
mainnet,
Expand All @@ -633,10 +618,6 @@ impl<'a> OwnedEnvironment<'a> {
LimitedCostTracker::new_free(),
epoch_id,
),
default_contract: ContractContext::new(
QualifiedContractIdentifier::transient(),
version,
),
call_stack: CallStack::new(),
}
}
Expand All @@ -648,13 +629,8 @@ impl<'a> OwnedEnvironment<'a> {
cost_tracker: LimitedCostTracker,
epoch_id: StacksEpochId,
) -> OwnedEnvironment<'a> {
let version = ClarityVersion::default_for_epoch(epoch_id);
OwnedEnvironment {
context: GlobalContext::new(mainnet, chain_id, database, cost_tracker, epoch_id),
default_contract: ContractContext::new(
QualifiedContractIdentifier::transient(),
version,
),
call_stack: CallStack::new(),
}
}
Expand All @@ -663,10 +639,11 @@ impl<'a> OwnedEnvironment<'a> {
&'b mut self,
sender: Option<PrincipalData>,
sponsor: Option<PrincipalData>,
context: &'b mut ContractContext,
) -> Environment<'b, 'a> {
Environment::new(
&mut self.context,
&self.default_contract,
context,
&mut self.call_stack,
sender.clone(),
sender,
Expand All @@ -678,6 +655,7 @@ impl<'a> OwnedEnvironment<'a> {
&mut self,
sender: PrincipalData,
sponsor: Option<PrincipalData>,
initial_context: Option<ContractContext>,
f: F,
) -> std::result::Result<(A, AssetMap, Vec<StacksTransactionEvent>), E>
where
Expand All @@ -688,7 +666,12 @@ impl<'a> OwnedEnvironment<'a> {
self.begin();

let result = {
let mut exec_env = self.get_exec_environment(Some(sender), sponsor);
let mut initial_context = initial_context.unwrap_or(ContractContext::new(
QualifiedContractIdentifier::transient(),
ClarityVersion::Clarity1,
));
let mut exec_env =
self.get_exec_environment(Some(sender), sponsor, &mut initial_context);
f(&mut exec_env)
};

Expand All @@ -704,6 +687,9 @@ impl<'a> OwnedEnvironment<'a> {
}
}

/// Initialize a contract with the "default" contract context (i.e. clarity1, transient ID).
/// No longer appropriate outside of testing, now that there are multiple clarity versions.
#[cfg(any(test, feature = "testing"))]
pub fn initialize_contract(
&mut self,
contract_identifier: QualifiedContractIdentifier,
Expand All @@ -713,23 +699,48 @@ impl<'a> OwnedEnvironment<'a> {
self.execute_in_env(
contract_identifier.issuer.clone().into(),
sponsor.clone(),
None,
|exec_env| exec_env.initialize_contract(contract_identifier, contract_content),
)
}

pub fn initialize_versioned_contract(
&mut self,
contract_identifier: QualifiedContractIdentifier,
version: ClarityVersion,
contract_content: &str,
sponsor: Option<PrincipalData>,
) -> Result<((), AssetMap, Vec<StacksTransactionEvent>)> {
self.execute_in_env(
contract_identifier.issuer.clone().into(),
sponsor.clone(),
Some(ContractContext::new(
QualifiedContractIdentifier::transient(),
version,
)),
|exec_env| exec_env.initialize_contract(contract_identifier, contract_content),
)
}

pub fn initialize_contract_from_ast(
&mut self,
contract_identifier: QualifiedContractIdentifier,
clarity_version: ClarityVersion,
contract_content: &ContractAST,
contract_string: &str,
sponsor: Option<PrincipalData>,
) -> Result<((), AssetMap, Vec<StacksTransactionEvent>)> {
self.execute_in_env(
contract_identifier.issuer.clone().into(),
sponsor.clone(),
Some(ContractContext::new(
QualifiedContractIdentifier::transient(),
clarity_version,
)),
|exec_env| {
exec_env.initialize_contract_from_ast(
contract_identifier,
clarity_version,
contract_content,
contract_string,
)
Expand All @@ -745,7 +756,7 @@ impl<'a> OwnedEnvironment<'a> {
tx_name: &str,
args: &[SymbolicExpression],
) -> Result<(Value, AssetMap, Vec<StacksTransactionEvent>)> {
self.execute_in_env(sender, sponsor, |exec_env| {
self.execute_in_env(sender, sponsor, None, |exec_env| {
exec_env.execute_contract(&contract_identifier, tx_name, args, false)
})
}
Expand All @@ -757,30 +768,35 @@ impl<'a> OwnedEnvironment<'a> {
amount: u128,
memo: &BuffData,
) -> Result<(Value, AssetMap, Vec<StacksTransactionEvent>)> {
self.execute_in_env(from.clone(), None, |exec_env| {
self.execute_in_env(from.clone(), None, None, |exec_env| {
exec_env.stx_transfer(from, to, amount, memo)
})
}

#[cfg(any(test, feature = "testing"))]
pub fn stx_faucet(&mut self, recipient: &PrincipalData, amount: u128) {
self.execute_in_env::<_, _, crate::vm::errors::Error>(recipient.clone(), None, |env| {
let mut snapshot = env
.global_context
.database
.get_stx_balance_snapshot(&recipient);
self.execute_in_env::<_, _, crate::vm::errors::Error>(
recipient.clone(),
None,
None,
|env| {
let mut snapshot = env
.global_context
.database
.get_stx_balance_snapshot(&recipient);

snapshot.credit(amount);
snapshot.save();
snapshot.credit(amount);
snapshot.save();

env.global_context
.database
.increment_ustx_liquid_supply(amount)
.unwrap();
env.global_context
.database
.increment_ustx_liquid_supply(amount)
.unwrap();

let res: std::result::Result<(), crate::vm::errors::Error> = Ok(());
res
})
let res: std::result::Result<(), crate::vm::errors::Error> = Ok(());
res
},
)
.unwrap();
}

Expand All @@ -792,6 +808,7 @@ impl<'a> OwnedEnvironment<'a> {
self.execute_in_env(
QualifiedContractIdentifier::transient().issuer.into(),
None,
None,
|exec_env| exec_env.eval_raw(program),
)
}
Expand All @@ -804,6 +821,7 @@ impl<'a> OwnedEnvironment<'a> {
self.execute_in_env(
QualifiedContractIdentifier::transient().issuer.into(),
None,
None,
|exec_env| exec_env.eval_read_only(contract, program),
)
}
Expand Down Expand Up @@ -1084,6 +1102,7 @@ impl<'a, 'b> Environment<'a, 'b> {
return Err(CheckErrors::CircularReference(vec![func_identifier.to_string()]).into())
}
self.call_stack.insert(&func_identifier, true);

let res = self.execute_function_as_transaction(&func, &args, Some(&contract.contract_context));
self.call_stack.remove(&func_identifier, true)?;

Expand Down Expand Up @@ -1178,12 +1197,18 @@ impl<'a, 'b> Environment<'a, 'b> {
clarity_version,
self.global_context.epoch_id,
)?;
self.initialize_contract_from_ast(contract_identifier, &contract_ast, &contract_content)
self.initialize_contract_from_ast(
contract_identifier,
clarity_version,
&contract_ast,
&contract_content,
)
}

pub fn initialize_contract_from_ast(
&mut self,
contract_identifier: QualifiedContractIdentifier,
contract_version: ClarityVersion,
contract_content: &ContractAST,
contract_string: &str,
) -> Result<()> {
Expand Down Expand Up @@ -1217,16 +1242,12 @@ impl<'a, 'b> Environment<'a, 'b> {
let memory_use = contract_string.len() as u64;
self.add_memory(memory_use)?;

let version = ClarityVersion::default_for_epoch(
self.global_context.database.get_clarity_epoch_version(),
);

let result = Contract::initialize_from_ast(
contract_identifier.clone(),
contract_content,
self.sponsor.clone(),
&mut self.global_context,
version,
contract_version,
);
self.drop_memory(memory_use);
result
Expand Down
Loading