sui_single_node_benchmark/tx_generator/
package_publish_tx_generator.rs1use crate::benchmark_context::BenchmarkContext;
5use crate::mock_account::Account;
6use crate::tx_generator::TxGenerator;
7use move_symbol_pool::Symbol;
8use serde::{Deserialize, Serialize};
9use std::collections::BTreeMap;
10use std::fs;
11use std::path::PathBuf;
12use sui_move_build::{BuildConfig, CompiledPackage};
13use sui_test_transaction_builder::{PublishData, TestTransactionBuilder};
14use sui_types::transaction::{DEFAULT_VALIDATOR_GAS_PRICE, Transaction};
15use tracing::info;
16
17pub struct PackagePublishTxGenerator {
18 compiled_package: CompiledPackage,
19}
20
21impl PackagePublishTxGenerator {
22 pub async fn new(ctx: &mut BenchmarkContext, manifest_path: PathBuf) -> Self {
23 let manifest = load_manifest_json(&manifest_path);
24 let dir = manifest_path.parent().unwrap();
25 let PackageDependencyManifest {
26 dependencies,
27 root_package,
28 } = manifest;
29 let mut dep_map = BTreeMap::new();
30 for dependency in dependencies {
31 let Package {
32 name,
33 path,
34 is_source_code,
35 } = dependency;
36
37 info!("Publishing dependent package {}", name);
38 let target_path = dir.join(&path);
39 let module_bytes = if is_source_code {
40 let compiled_package = BuildConfig::new_for_testing()
41 .build_async(&target_path)
42 .await
43 .unwrap();
44 compiled_package.get_package_bytes(false)
45 } else {
46 let module_dir = target_path
47 .join("build")
48 .join(name.clone())
49 .join("bytecode_modules");
50 let mut all_bytes = Vec::new();
51 info!("Loading module bytes from {:?}", module_dir);
52 for entry in fs::read_dir(module_dir).unwrap() {
53 let entry = entry.unwrap();
54 let file_path = entry.path();
55 if file_path.extension().and_then(|s| s.to_str()) == Some("mv") {
56 let contents = fs::read(file_path).unwrap();
57 all_bytes.push(contents);
58 }
59 }
60 all_bytes
61 };
62 let package_id = ctx
63 .publish_package(PublishData::ModuleBytes(module_bytes))
64 .await
65 .0;
66 info!("Published dependent package {}", package_id);
67 dep_map.insert(Symbol::from(name), package_id);
68 }
69
70 let Package {
71 name,
72 path,
73 is_source_code,
74 } = root_package;
75
76 info!("Compiling root package {}", name);
77 assert!(
78 is_source_code,
79 "Only support building root package from source code"
80 );
81
82 let target_path = dir.join(path);
83 let published_deps = dep_map.clone();
84
85 let mut compiled_package = BuildConfig::new_for_testing_replace_addresses(
86 dep_map.into_iter().map(|(k, v)| (k.to_string(), v)),
87 )
88 .build_async(&target_path)
89 .await
90 .unwrap();
91
92 compiled_package.dependency_ids.published = published_deps;
93 Self { compiled_package }
94 }
95}
96
97impl TxGenerator for PackagePublishTxGenerator {
98 fn generate_tx(&self, account: Account) -> Transaction {
99 TestTransactionBuilder::new(
100 account.sender,
101 account.gas_objects[0],
102 DEFAULT_VALIDATOR_GAS_PRICE,
103 )
104 .publish_with_data(PublishData::CompiledPackage(self.compiled_package.clone()))
105 .build_and_sign(account.keypair.as_ref())
106 }
107
108 fn name(&self) -> &'static str {
109 "PackagePublishTxGenerator"
110 }
111}
112
113#[derive(Serialize, Deserialize, Debug)]
114struct PackageDependencyManifest {
115 dependencies: Vec<Package>,
116 root_package: Package,
117}
118
119#[derive(Serialize, Deserialize, Debug)]
120struct Package {
121 name: String,
122 path: PathBuf,
123 is_source_code: bool,
124}
125
126fn load_manifest_json(file_path: &PathBuf) -> PackageDependencyManifest {
127 let data = fs::read_to_string(file_path)
128 .unwrap_or_else(|_| panic!("Unable to read file at: {:?}", file_path));
129 let parsed_data: PackageDependencyManifest = serde_json::from_str(&data)
130 .unwrap_or_else(|_| panic!("Unable to parse json from file at: {:?}", file_path));
131
132 parsed_data
133}