Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Cargo.lock

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

19 changes: 19 additions & 0 deletions src/block/src/shard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::{
use std::{
any::type_name,
fmt::{self, Display, Formatter},
str::FromStr,
};

#[cfg(test)]
Expand Down Expand Up @@ -644,6 +645,24 @@ impl fmt::Debug for ShardIdent {
}
}

impl FromStr for ShardIdent {
type Err = crate::Error;

fn from_str(s: &str) -> Result<Self> {
let (workchain_part, shard_part_with_maybe_extra) =
s.split_once(':').ok_or_else(|| error!("Can't read shard ident from {}", s))?;

let workchain_id: i32 = workchain_part
.trim()
.parse()
.map_err(|e| error!("Can't read workchain_id from {}: {}", s, e))?;
let prefix = u64::from_str_radix(shard_part_with_maybe_extra.trim(), 16)
.map_err(|e| error!("Can't read shard from {}: {}", s, e))?;

Ok(Self { workchain_id, prefix })
}
}

impl Deserializable for ShardIdent {
fn read_from(&mut self, cell: &mut SliceData) -> Result<()> {
let constructor_and_pfx = cell.get_next_byte()?;
Expand Down
6 changes: 6 additions & 0 deletions src/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ path = 'bin/print.rs'
name = 'zerostate'
path = 'bin/zerostate.rs'

[[bin]]
name = 'archive_import'
path = 'bin/archive_import.rs'

[[bin]]
name = 'hardfork'
path = 'bin/hardfork.rs'
Expand Down Expand Up @@ -73,6 +77,7 @@ num_cpus = '1.13'
openssl = '0.10'
parking_lot = '0.12'
rand = '0.8'
rayon = '1'
regex = '1.10'
serde = '1.0'
serde_derive = '1.0'
Expand Down Expand Up @@ -110,6 +115,7 @@ harness = false

[dev-dependencies]
criterion = { version = "0.5", features = ["html_reports", "async_tokio"] }
tempfile = '3'
difference = '2.0'
external-ip = '6.0'
http-body-util = "0.1"
Expand Down
102 changes: 102 additions & 0 deletions src/node/bin/archive_import.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (C) 2025-2026 RSquad Blockchain Lab.
*
* Licensed under the GNU General Public License v3.0.
* See the LICENSE file in the root of this repository.
*
* This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND.
*/
use clap::{Arg, ArgAction, Command};
use node::archive_import::{run_import, ImportConfig};
use std::path::PathBuf;

fn main() {
env_logger::Builder::from_default_env().format_timestamp_millis().init();

let matches = Command::new("archive_import")
.about("Import raw .pack archive files into epoch-based storage")
.arg(
Arg::new("archives-path")
.long("archives-path")
.required(true)
.help("Path to directory with source .pack files"),
)
.arg(
Arg::new("epochs-path")
.long("epochs-path")
.required(true)
.help("Path where epoch directories will be created"),
)
.arg(
Arg::new("epoch-size")
.long("epoch-size")
.default_value("10000000")
.help("Number of MC blocks per epoch (must be multiple of 20000)"),
)
.arg(
Arg::new("node-db-path")
.long("node-db-path")
.required(true)
.help("Path to node database directory"),
)
.arg(
Arg::new("mc-zerostate")
.long("mc-zerostate")
.required(true)
.help("Path to masterchain zerostate .boc file"),
)
.arg(
Arg::new("wc-zerostate")
.long("wc-zerostate")
.action(ArgAction::Append)
.required(true)
.help("Path to workchain zerostate .boc file (one per workchain)"),
)
.arg(
Arg::new("global-config")
.long("global-config")
.required(true)
.help("Path to global config JSON file (describes zerostate and hard forks)"),
)
.arg(
Arg::new("skip-validation")
.long("skip-validation")
.action(ArgAction::SetTrue)
.help("Skip block proof validation (for re-importing already validated archives)"),
)
.arg(Arg::new("copy").long("copy").action(ArgAction::SetTrue).help(
"Copy source .pack files instead of moving them. Use for keeping original \
files or when source and destination are on different filesystems.",
))
.get_matches();

let config = ImportConfig {
archives_path: PathBuf::from(matches.get_one::<String>("archives-path").unwrap()),
epochs_path: PathBuf::from(matches.get_one::<String>("epochs-path").unwrap()),
epoch_size: matches
.get_one::<String>("epoch-size")
.unwrap()
.parse()
.expect("epoch-size must be a number"),
node_db_path: PathBuf::from(matches.get_one::<String>("node-db-path").unwrap()),
mc_zerostate_path: PathBuf::from(matches.get_one::<String>("mc-zerostate").unwrap()),
wc_zerostate_paths: matches
.get_many::<String>("wc-zerostate")
.unwrap()
.map(|s| PathBuf::from(s))
.collect(),
global_config_path: PathBuf::from(matches.get_one::<String>("global-config").unwrap()),
skip_validation: matches.get_flag("skip-validation"),
move_files: !matches.get_flag("copy"),
};

let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("Failed to create tokio runtime");

if let Err(e) = rt.block_on(run_import(config)) {
log::error!("Import failed: {}", e);
std::process::exit(1);
}
}
Loading
Loading