sui_single_node_benchmark/tx_generator/
package_publish_tx_generator.rs

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