Skip to content

Commit a340d48

Browse files
authored
feat: handle deployment plans in simnet (#1360)
* feat: handle deployment plans in simnet * chore: update clarity * refactor: improve simnet deployment plan handling and vfs * test: custom deployment plan in simnet * feat: keep customs txs when generating a new deployment plan in simnet * tests: deployment plan behaviour in simnet * chore: bump sdk version * refactor: revert vfs changes * chore: bump sdk version
1 parent 80be703 commit a340d48

File tree

27 files changed

+902
-564
lines changed

27 files changed

+902
-564
lines changed

Cargo.lock

Lines changed: 129 additions & 249 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/clarinet-cli/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ segment = { version = "0.1.2", optional = true }
5858
mac_address = { version = "1.1.2", optional = true }
5959
tower-lsp = { version = "0.19.0", optional = true }
6060
hex = "0.4.3"
61-
serde_yaml = "0.8.23"
6261
num_cpus = "1.13.1"
6362
mio = "0.8"
6463
similar = "2.1.0"

components/clarinet-cli/src/deployments/mod.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,6 @@ pub fn write_deployment(
101101
}
102102
}
103103

104-
let file = deployment.to_specification_file();
105-
106-
let content = match serde_yaml::to_string(&file) {
107-
Ok(res) => res,
108-
Err(err) => return Err(format!("failed serializing deployment\n{}", err)),
109-
};
110-
111-
target_location.write_content(content.as_bytes())?;
104+
target_location.write_content(&deployment.to_file_content()?)?;
112105
Ok(())
113106
}

components/clarinet-cli/src/deployments/types.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,16 @@ impl DeploymentSynthesis {
2929
}
3030
}
3131
}
32-
let file = deployment.to_specification_file();
33-
let content = match serde_yaml::to_string(&file) {
32+
33+
let content = match deployment.to_file_content() {
3434
Ok(res) => res,
3535
Err(err) => panic!("unable to serialize deployment {}", err),
3636
};
37+
3738
DeploymentSynthesis {
3839
total_cost,
3940
blocks_count,
40-
content,
41+
content: std::str::from_utf8(&content).unwrap().to_string(),
4142
}
4243
}
4344
}

components/clarinet-cli/src/frontend/cli.rs

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -618,21 +618,16 @@ pub fn main() {
618618
}
619619

620620
let write_plan = if default_deployment_path.exists() {
621-
let existing_deployment =
622-
match load_deployment(&manifest, &default_deployment_path) {
623-
Ok(deployment) => deployment,
624-
Err(message) => {
625-
println!(
626-
"{}",
627-
format_err!(format!(
628-
"unable to load {}\n{}",
629-
default_deployment_path.to_string(),
630-
message
631-
))
632-
);
633-
process::exit(1);
634-
}
635-
};
621+
let existing_deployment = load_deployment(&manifest, &default_deployment_path)
622+
.unwrap_or_else(|message| {
623+
println!(
624+
"{}",
625+
format_err!(format!(
626+
"unable to load {default_deployment_path}\n{message}",
627+
))
628+
);
629+
process::exit(1);
630+
});
636631
should_existing_plan_be_replaced(&existing_deployment, &deployment)
637632
} else {
638633
true
@@ -1300,23 +1295,29 @@ fn load_deployment_and_artifacts_or_exit(
13001295
}
13011296
}
13021297

1303-
pub fn should_existing_plan_be_replaced(
1298+
fn should_existing_plan_be_replaced(
13041299
existing_plan: &DeploymentSpecification,
13051300
new_plan: &DeploymentSpecification,
13061301
) -> bool {
13071302
use similar::{ChangeTag, TextDiff};
13081303

1309-
let existing_file = serde_yaml::to_string(&existing_plan.to_specification_file()).unwrap();
1310-
1311-
let new_file = serde_yaml::to_string(&new_plan.to_specification_file()).unwrap();
1304+
let existing_file = existing_plan
1305+
.to_file_content()
1306+
.expect("unable to serialize deployment");
1307+
let new_file = new_plan
1308+
.to_file_content()
1309+
.expect("unable to serialize deployment");
13121310

13131311
if existing_file == new_file {
13141312
return false;
13151313
}
13161314

13171315
println!("{}", blue!("A new deployment plan was computed and differs from the default deployment plan currently saved on disk:"));
13181316

1319-
let diffs = TextDiff::from_lines(&existing_file, &new_file);
1317+
let diffs = TextDiff::from_lines(
1318+
std::str::from_utf8(&existing_file).unwrap(),
1319+
std::str::from_utf8(&new_file).unwrap(),
1320+
);
13201321

13211322
for change in diffs.iter_all_changes() {
13221323
let formatted_change = match change.tag() {
@@ -1338,7 +1339,7 @@ pub fn should_existing_plan_be_replaced(
13381339
!buffer.starts_with('n')
13391340
}
13401341

1341-
pub fn load_deployment_if_exists(
1342+
fn load_deployment_if_exists(
13421343
manifest: &ProjectManifest,
13431344
network: &StacksNetwork,
13441345
force_on_disk: bool,
@@ -1357,13 +1358,12 @@ pub fn load_deployment_if_exists(
13571358
Ok((deployment, _)) => {
13581359
use similar::{ChangeTag, TextDiff};
13591360

1360-
let current_version = match default_deployment_location.read_content_as_utf8() {
1361+
let current_version = match default_deployment_location.read_content() {
13611362
Ok(content) => content,
13621363
Err(message) => return Some(Err(message)),
13631364
};
13641365

1365-
let file = deployment.to_specification_file();
1366-
let updated_version = match serde_yaml::to_string(&file) {
1366+
let updated_version = match deployment.to_file_content() {
13671367
Ok(res) => res,
13681368
Err(err) => {
13691369
return Some(Err(format!("failed serializing deployment\n{}", err)))
@@ -1377,7 +1377,10 @@ pub fn load_deployment_if_exists(
13771377
if !force_computed {
13781378
println!("{}", blue!("A new deployment plan was computed and differs from the default deployment plan currently saved on disk:"));
13791379

1380-
let diffs = TextDiff::from_lines(&current_version, &updated_version);
1380+
let diffs = TextDiff::from_lines(
1381+
std::str::from_utf8(&current_version).unwrap(),
1382+
std::str::from_utf8(&updated_version).unwrap(),
1383+
);
13811384

13821385
for change in diffs.iter_all_changes() {
13831386
let formatted_change = match change.tag() {
@@ -1399,13 +1402,13 @@ pub fn load_deployment_if_exists(
13991402
Some(load_deployment(manifest, &default_deployment_location))
14001403
} else {
14011404
default_deployment_location
1402-
.write_content(updated_version.as_bytes())
1405+
.write_content(&updated_version)
14031406
.ok()?;
14041407
Some(Ok(deployment))
14051408
}
14061409
} else {
14071410
default_deployment_location
1408-
.write_content(updated_version.as_bytes())
1411+
.write_content(&updated_version)
14091412
.ok()?;
14101413
Some(Ok(deployment))
14111414
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
use std::collections::BTreeMap;
2+
3+
use clarinet_files::{chainhook_types::StacksNetwork, FileLocation};
4+
use clarity_repl::clarity::{
5+
vm::types::{QualifiedContractIdentifier, StandardPrincipalData},
6+
ClarityName, ClarityVersion, ContractName,
7+
};
8+
9+
use crate::types::*;
10+
11+
fn get_test_txs() -> (TransactionSpecification, TransactionSpecification) {
12+
let contract_id =
13+
QualifiedContractIdentifier::parse("ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.test")
14+
.unwrap();
15+
let tx_sender = StandardPrincipalData::from(contract_id.issuer.clone());
16+
17+
let contract_publish_tx =
18+
TransactionSpecification::EmulatedContractPublish(EmulatedContractPublishSpecification {
19+
contract_name: ContractName::try_from("test".to_string()).unwrap(),
20+
emulated_sender: tx_sender.clone(),
21+
location: FileLocation::from_path_string("/contracts/test.clar").unwrap(),
22+
source: "(ok true)".to_string(),
23+
clarity_version: ClarityVersion::Clarity2,
24+
});
25+
26+
let contract_call_txs =
27+
TransactionSpecification::EmulatedContractCall(EmulatedContractCallSpecification {
28+
contract_id: QualifiedContractIdentifier::parse(
29+
"ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.test",
30+
)
31+
.unwrap(),
32+
emulated_sender: tx_sender.clone(),
33+
method: ClarityName::try_from("test".to_string()).unwrap(),
34+
parameters: vec![],
35+
});
36+
37+
(contract_publish_tx, contract_call_txs)
38+
}
39+
40+
fn build_test_deployement_plan(
41+
batches: Vec<TransactionsBatchSpecification>,
42+
) -> DeploymentSpecification {
43+
DeploymentSpecification {
44+
id: 1,
45+
name: "test".to_string(),
46+
network: StacksNetwork::Simnet,
47+
stacks_node: None,
48+
bitcoin_node: None,
49+
genesis: None,
50+
contracts: BTreeMap::new(),
51+
plan: TransactionPlanSpecification { batches },
52+
}
53+
}
54+
55+
#[test]
56+
fn test_extract_no_contract_publish_txs() {
57+
let (contract_publish_tx, contract_call_txs) = get_test_txs();
58+
59+
let plan = build_test_deployement_plan(vec![
60+
TransactionsBatchSpecification {
61+
id: 0,
62+
transactions: vec![contract_publish_tx.clone()],
63+
epoch: Some(EpochSpec::Epoch2_4),
64+
},
65+
TransactionsBatchSpecification {
66+
id: 1,
67+
transactions: vec![contract_call_txs.clone()],
68+
epoch: Some(EpochSpec::Epoch2_4),
69+
},
70+
]);
71+
72+
let (new_plan, custom_txs) = plan.extract_no_contract_publish_txs();
73+
74+
assert_eq!(
75+
new_plan,
76+
build_test_deployement_plan(vec![TransactionsBatchSpecification {
77+
id: 0,
78+
transactions: vec![contract_publish_tx.clone()],
79+
epoch: Some(EpochSpec::Epoch2_4),
80+
},])
81+
);
82+
83+
assert_eq!(
84+
custom_txs,
85+
vec![TransactionsBatchSpecification {
86+
id: 1,
87+
transactions: vec![contract_call_txs.clone()],
88+
epoch: Some(EpochSpec::Epoch2_4),
89+
}]
90+
);
91+
}
92+
93+
#[test]
94+
fn test_merge_batches() {
95+
let (contract_publish_tx, contract_call_txs) = get_test_txs();
96+
97+
let plan = build_test_deployement_plan(vec![
98+
TransactionsBatchSpecification {
99+
id: 0,
100+
transactions: vec![contract_publish_tx.clone()],
101+
epoch: Some(EpochSpec::Epoch2_4),
102+
},
103+
TransactionsBatchSpecification {
104+
id: 1,
105+
transactions: vec![contract_call_txs.clone()],
106+
epoch: Some(EpochSpec::Epoch2_4),
107+
},
108+
]);
109+
110+
let (mut new_plan, custom_txs) = plan.extract_no_contract_publish_txs();
111+
112+
assert_ne!(plan, new_plan);
113+
114+
new_plan.merge_batches(custom_txs);
115+
116+
assert_eq!(plan, new_plan);
117+
}

components/clarinet-deployments/src/lib.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ pub mod onchain;
1313
pub mod requirements;
1414
pub mod types;
1515

16+
#[cfg(test)]
17+
mod deployment_plan_test;
18+
1619
use self::types::{
1720
DeploymentSpecification, EmulatedContractPublishSpecification, GenesisSpecification,
1821
TransactionPlanSpecification, TransactionsBatchSpecification, WalletSpecification,
@@ -564,9 +567,7 @@ pub async fn generate_default_deployment(
564567
contract_location.to_string()
565568
})
566569
.collect();
567-
file_accessor
568-
.read_contracts_content(contracts_location)
569-
.await?
570+
file_accessor.read_files(contracts_location).await?
570571
}
571572
};
572573

0 commit comments

Comments
 (0)