Skip to content

Commit

Permalink
support test file creation as a part of test txn generation
Browse files Browse the repository at this point in the history
  • Loading branch information
yuunlimm committed Jan 9, 2025
1 parent 4ff0a0c commit 3822921
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 110 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion ecosystem/indexer-grpc/indexer-test-transactions/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ publish = { workspace = true }
repository = { workspace = true }
rust-version = { workspace = true }

[dependencies]
[build-dependencies]
aptos-indexer-transaction-generator = { workspace = true }
aptos-protos ={ workspace = true }
serde_json = { workspace = true }
127 changes: 23 additions & 104 deletions ecosystem/indexer-grpc/indexer-test-transactions/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,110 +2,11 @@
// SPDX-License-Identifier: Apache-2.0

use std::{env, fs, path::Path};

const IMPORTED_MAINNET_TXNS: &str = "imported_mainnet_txns";
const IMPORTED_TESTNET_TXNS: &str = "imported_testnet_txns";
const IMPORTED_DEVNET_TXNS: &str = "imported_devnet_txns";
const SCRIPTED_TRANSACTIONS_TXNS: &str = "scripted_transactions";
#[derive(Default)]
pub struct TransactionCodeBuilder {
// Holds the generated Rust code for transaction constants
transactions_code: String,
// Holds the match arms for the name generation function for scripted txns (optional)
name_function_code: String,
}

impl TransactionCodeBuilder {
pub fn new() -> Self {
Self::default()
}

pub fn add_directory(
mut self,
dir_name: &str,
module_name: &str,
generate_name_function: bool,
) -> Self {
let json_dir = Path::new("json_transactions").join(dir_name);
let mut all_constants = String::new();

// Iterates over all files in the directory
for entry in fs::read_dir(json_dir).expect("Failed to read directory") {
let entry = entry.expect("Failed to get directory entry");
let path = entry.path();

// Checks if the file has a `.json` extension
if path.extension().and_then(|s| s.to_str()) == Some("json") {
let file_name = path.file_stem().unwrap().to_str().unwrap();
let const_name = format!(
"{}_{}",
module_name.to_uppercase(),
file_name.to_uppercase().replace('-', "_")
);

// Generates a constant for the JSON file and appends it to the `transactions_code` string
self.transactions_code.push_str(&format!(
r#"
pub const {const_name}: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/json_transactions/{dir_name}/{file_name}.json"));
"#,
const_name = const_name,
dir_name = dir_name,
file_name = file_name,
));

// Adds the constant to the list of all constants
all_constants.push_str(&format!("{},", const_name));

// If name function generation is requested, adds the corresponding match arm
if generate_name_function {
self.name_function_code.push_str(&format!(
" {const_name} => Some(\"{file_name}\"),\n",
const_name = const_name,
file_name = file_name
));
}
}
}

// If any constants were created, generate an array holding all of them
if !all_constants.is_empty() {
self.transactions_code.push_str(&format!(
"pub const ALL_{}: &[&[u8]] = &[{}];\n",
module_name.to_uppercase(),
all_constants
));
}

self
}

// Adds the transaction name lookup function if any name match arms were created
pub fn add_transaction_name_function(mut self) -> Self {
if !self.name_function_code.is_empty() {
self.transactions_code.push_str(
r#"
pub fn get_transaction_name(const_data: &[u8]) -> Option<&'static str> {
match const_data {
"#,
);

self.transactions_code.push_str(&self.name_function_code);

self.transactions_code.push_str(
r#"
_ => None,
}
}
"#,
);
}
self
}

pub fn build(self) -> String {
self.transactions_code
}
}
use aptos_indexer_transaction_generator::transaction_code_builder::TransactionCodeBuilder;

fn main() {
let out_dir = env::var("OUT_DIR").unwrap();
Expand All @@ -117,12 +18,30 @@ fn main() {
create_directory_if_missing(&format!("json_transactions/{}", IMPORTED_DEVNET_TXNS));
create_directory_if_missing(&format!("json_transactions/{}", SCRIPTED_TRANSACTIONS_TXNS));

let output_dir = Path::new("json_transactions");

// Using the builder pattern to construct the code
let code = TransactionCodeBuilder::new()
.add_directory(IMPORTED_MAINNET_TXNS, IMPORTED_MAINNET_TXNS, false)
.add_directory(IMPORTED_TESTNET_TXNS, IMPORTED_TESTNET_TXNS, false)
.add_directory(IMPORTED_DEVNET_TXNS, IMPORTED_DEVNET_TXNS, false)
.add_directory(SCRIPTED_TRANSACTIONS_TXNS, SCRIPTED_TRANSACTIONS_TXNS, true)
.add_directory(
output_dir.join(IMPORTED_MAINNET_TXNS).as_path(),
IMPORTED_MAINNET_TXNS,
false,
)
.add_directory(
output_dir.join(IMPORTED_TESTNET_TXNS).as_path(),
IMPORTED_TESTNET_TXNS,
false,
)
.add_directory(
output_dir.join(IMPORTED_DEVNET_TXNS).as_path(),
IMPORTED_DEVNET_TXNS,
false,
)
.add_directory(
output_dir.join(SCRIPTED_TRANSACTIONS_TXNS).as_path(),
SCRIPTED_TRANSACTIONS_TXNS,
true,
)
.add_transaction_name_function()
.build();

Expand Down
37 changes: 32 additions & 5 deletions ecosystem/indexer-grpc/indexer-transaction-generator/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ use crate::{accont_manager::AccountManager, managed_node::ManagedNode};
use anyhow::Context;
use clap::Parser;
use serde::{Deserialize, Serialize};
use std::{
collections::{HashMap, HashSet},
path::{Path, PathBuf},
};
use std::{collections::{HashMap, HashSet}, fs, path::{Path, PathBuf}};
use url::Url;
use crate::transaction_code_builder::{IMPORTED_MAINNET_TXNS, IMPORTED_TESTNET_TXNS, SCRIPTED_TRANSACTIONS_TXNS, TransactionCodeBuilder};

const SCRIPTED_TRANSACTIONS_FOLDER: &str = "scripted_transactions";
const MOVE_SCRIPTS_FOLDER: &str = "move_fixtures";
Expand All @@ -28,6 +26,13 @@ pub struct IndexerCliArgs {
/// Path to the output folder where the generated transactions will be saved.
#[clap(long)]
pub output_folder: PathBuf,

/// Path to the rust file to generate the transactions code.
#[clap(long)]
pub rust_file: Option<PathBuf>,

#[clap(short, long)]
pub create_rust_file: bool,
}

impl IndexerCliArgs {
Expand Down Expand Up @@ -140,7 +145,29 @@ impl IndexerCliArgs {
))?;
}
// Stop the localnet.
managed_node.stop().await
managed_node.stop().await?;

if self.create_rust_file {
let dest_path = self.rust_file.as_ref()
.ok_or_else(|| anyhow::anyhow!("No rust_file path provided"))?;
let output_dir = Path::new(&self.output_folder);

// Using the builder pattern to construct the code
let code = TransactionCodeBuilder::new()
.add_directory(output_dir.join(IMPORTED_MAINNET_TXNS).as_path(), IMPORTED_MAINNET_TXNS, false)
.add_directory(output_dir.join(IMPORTED_TESTNET_TXNS).as_path(), IMPORTED_TESTNET_TXNS, false)
.add_directory(output_dir.join(SCRIPTED_TRANSACTIONS_TXNS).as_path(), SCRIPTED_TRANSACTIONS_TXNS, true)
.add_transaction_name_function()
.build();

match fs::write(dest_path, code) {
Ok(_) => println!("Successfully generated the transactions code."),
Err(e) => println!("Failed to generate the transactions code for dest_path:{:?}, {:?}", dest_path, e),
}
Ok(())
} else {
Ok(())
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pub mod config;
pub mod managed_node;
pub mod script_transaction_generator;
pub mod transaction_importer;
pub mod transaction_code_builder;
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright (c) Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

use std::fs;
use std::path::Path;

pub const IMPORTED_MAINNET_TXNS: &str = "imported_mainnet_txns";
pub const IMPORTED_TESTNET_TXNS: &str = "imported_testnet_txns";
pub const SCRIPTED_TRANSACTIONS_TXNS: &str = "scripted_transactions";

#[derive(Default)]
pub struct TransactionCodeBuilder {
// Holds the generated Rust code for transaction constants
transactions_code: String,
// Holds the match arms for the name generation function for scripted txns (optional)
name_function_code: String,
}

impl TransactionCodeBuilder {
pub fn new() -> Self {
Self::default()
}

/**
* Adds a directory of JSON files to the transaction code builder.
*
* @param src_dir: The source directory containing the JSON files
* @param dir_name: The name of the directory to be created in the `json_transactions` directory
* @param module_name: The name of the module to be used in the constant names
* @param generate_name_function: Whether to generate a transaction name lookup function
*/
pub fn add_directory(
mut self,
json_dir: &Path,
module_name: &str,
generate_name_function: bool,
) -> Self {
let mut all_constants = String::new();

// Iterates over all files in the directory
for entry in fs::read_dir(json_dir).expect("Failed to read directory") {
let entry = entry.expect("Failed to get directory entry");
let path = entry.path();

// Checks if the file has a `.json` extension
if path.extension().and_then(|s| s.to_str()) == Some("json") {
let file_name = path.file_stem().unwrap().to_str().unwrap();
let const_name = format!(
"{}_{}",
module_name.to_uppercase(),
file_name.to_uppercase().replace('-', "_")
);

// Generates a constant for the JSON file and appends it to the `transactions_code` string
self.transactions_code.push_str(&format!(
r#"
pub const {const_name}: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/json_transactions/{dir_name}/{file_name}.json"));
"#,
const_name = const_name,
dir_name = module_name,
file_name = file_name,
));

// Adds the constant to the list of all constants
all_constants.push_str(&format!("{},", const_name));

// If name function generation is requested, adds the corresponding match arm
if generate_name_function {
self.name_function_code.push_str(&format!(
" {const_name} => Some(\"{file_name}\"),\n",
const_name = const_name,
file_name = file_name
));
}
}
}

// If any constants were created, generate an array holding all of them
if !all_constants.is_empty() {
self.transactions_code.push_str(&format!(
"pub const ALL_{}: &[&[u8]] = &[{}];\n",
module_name.to_uppercase(),
all_constants
));
}

self
}

// Adds the transaction name lookup function if any name match arms were created
pub fn add_transaction_name_function(mut self) -> Self {
if !self.name_function_code.is_empty() {
self.transactions_code.push_str(
r#"
pub fn get_transaction_name(const_data: &[u8]) -> Option<&'static str> {
match const_data {
"#,
);

self.transactions_code.push_str(&self.name_function_code);

self.transactions_code.push_str(
r#"
_ => None,
}
}
"#,
);
}
self
}

pub fn build(self) -> String {
self.transactions_code
}
}

0 comments on commit 3822921

Please sign in to comment.