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