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_symbol_pool::Symbol;
8use serde::{Deserialize, Serialize};
9use std::collections::BTreeMap;
10use std::fs;
11use std::path::PathBuf;
12use sui_move_build::{BuildConfig, CompiledPackage, PublishedDependency};
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
84            .iter()
85            .map(|(name, published_at)| {
86                (*name, PublishedDependency::new(*name, *name, *published_at))
87            })
88            .collect();
89
90        let mut compiled_package = BuildConfig::new_for_testing_replace_addresses(
91            dep_map.into_iter().map(|(k, v)| (k.to_string(), v)),
92        )
93        .build_async(&target_path)
94        .await
95        .unwrap();
96
97        compiled_package.dependency_ids.published = published_deps;
98        Self { compiled_package }
99    }
100}
101
102impl TxGenerator for PackagePublishTxGenerator {
103    fn generate_tx(&self, account: Account) -> Transaction {
104        TestTransactionBuilder::new(
105            account.sender,
106            account.gas_objects[0],
107            DEFAULT_VALIDATOR_GAS_PRICE,
108        )
109        .publish_with_data(PublishData::CompiledPackage(self.compiled_package.clone()))
110        .build_and_sign(account.keypair.as_ref())
111    }
112
113    fn name(&self) -> &'static str {
114        "PackagePublishTxGenerator"
115    }
116}
117
118#[derive(Serialize, Deserialize, Debug)]
119struct PackageDependencyManifest {
120    dependencies: Vec<Package>,
121    root_package: Package,
122}
123
124#[derive(Serialize, Deserialize, Debug)]
125struct Package {
126    name: String,
127    path: PathBuf,
128    is_source_code: bool,
129}
130
131fn load_manifest_json(file_path: &PathBuf) -> PackageDependencyManifest {
132    let data = fs::read_to_string(file_path)
133        .unwrap_or_else(|_| panic!("Unable to read file at: {:?}", file_path));
134    let parsed_data: PackageDependencyManifest = serde_json::from_str(&data)
135        .unwrap_or_else(|_| panic!("Unable to parse json from file at: {:?}", file_path));
136
137    parsed_data
138}