Skip to content

Commit

Permalink
feat(cli): git init installs genesis file
Browse files Browse the repository at this point in the history
kindelia_core:
* genesis.kdl file removed. (moved into kindelia/genesis/networks)
* genesis Statements are passed to kindelia_core api, not network_id
* added kindelia_core/genesis-tests.kdl for core test cases
* updated test cases
* remove empty constants.rs
* remove genesis_path().  (moved into kindelia/src/genesis.rs)

kindelia:
* all genesis files get compiled into kindelia executable
* latest (by name) genesis file gets installed by kindelia init
* add kindelia/genesis/README.md
* add genesis.rs and move some util fn into it
* cargo add include_dir
* cargo fmt fixes
* parse genesis statements in 'node start' and 'test'
* update test(s)
  • Loading branch information
dan-da committed Nov 28, 2022
1 parent acd8b21 commit f6435eb
Show file tree
Hide file tree
Showing 16 changed files with 330 additions and 62 deletions.
31 changes: 31 additions & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions kindelia/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ fastrand = "1.7.0"
dirs = "4.0.0"
hex = "0.4"
derive_builder = "0.11.2"
include_dir = "0.7.3"

# CLI / configuration
clap = { version = "4.0.18", features = ["derive"] }
Expand All @@ -49,6 +50,8 @@ serde_json = "1.0"
# Events API
tokio = { version = "1.19.1", features = ["sync"] }

# Errors
thiserror = "1.0.37"

[dev-dependencies]
assert_cmd = "1.0.1"
Expand Down
18 changes: 18 additions & 0 deletions kindelia/genesis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# About this directory

The `genesis/networks` directory holds genesis block files, one per network.

Important! All files inside the `networks` sub-directory get compiled into the
`kindelia` executable. So please do not put any other type of file inside and
observe the naming convention.

The files are named to match hexadecimal network identifiers as specified
in the config file with extension `.kdl`. For example, `network/0xCAFE0006.kdl` corresponds to network `0xCAFE0006`.

Typically a new network is created by bumping this value, eg creating the
file `networks/0xCAFE0007.kdl`. Also `../default.toml` should be updated to match.

The genesis file with the highest hex value is installed into the
user's home directory when `kindelia init` is run.


File renamed without changes.
79 changes: 79 additions & 0 deletions kindelia/src/genesis.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
use include_dir::{include_dir, Dir, File};
use std::path::{Path, PathBuf};
use thiserror::Error;

#[derive(Error, Debug)]
pub enum GenesisPathError {
#[error("Home directory not found")]
HomeDirNotFound,
#[error("File not found in {0}")]
FileNotFound(PathBuf),
}

pub fn genesis_path(network_id: u32) -> Result<PathBuf, GenesisPathError> {
let path = dirs::home_dir()
.ok_or(GenesisPathError::HomeDirNotFound)?
.join(".kindelia")
.join("genesis")
.join(format!("{:#02X}.kdl", network_id));
match path.exists() {
true => Ok(path),
false => Err(GenesisPathError::FileNotFound(path)),
}
}

#[derive(Error, Debug)]
pub enum GenesisCodeError {
#[error(transparent)]
PathError(#[from] GenesisPathError),

#[error("Genesis block could not be read from {path:?}.")]
ReadError { path: PathBuf, cause: std::io::Error },
}

pub fn genesis_code(network_id: u32) -> Result<String, GenesisCodeError> {
let path = genesis_path(network_id)?;
std::fs::read_to_string(&path)
.map_err(|e| GenesisCodeError::ReadError { path, cause: e })
}

#[derive(Error, Debug)]
pub enum InitGenesisError {
#[error("Could not create directory: {path:?}")]
DirNotCreated { path: std::path::PathBuf, cause: std::io::Error },
#[error("Unable to write genesis file: {path:?}")]
FileNotWritten { path: std::path::PathBuf, cause: std::io::Error },
#[error("Genesis file is missing from the executable")]
Missing,
}

static GENESIS_DIR: Dir<'_> =
include_dir!("$CARGO_MANIFEST_DIR/genesis/networks");

/// Copies latest file from kindelia_core/genesis to <homedir>/.kindelia/genesis
/// Creates target dir if not existing.
///
/// The way this works is that all the files in kindelia_core/genesis get compiled
/// into the executable by the include_dir!() macro. With this trick we are able
/// to include files dynamically, whereas include_str!() requires a static str.
///
/// note: we could copy over all files from kindelia_core/genesis instead.
pub fn init_genesis(dir_path: &Path) -> Result<(), InitGenesisError> {
let mut files: Vec<&File> = GENESIS_DIR.files().collect();

// files should be named as hex values, so we sort case insensitively
// The goal here is to find highest numeric (hex) value.
files.sort_by_cached_key(|f| f.path().as_os_str().to_ascii_uppercase());

let file = files.last().ok_or(InitGenesisError::Missing)?;
let fname = file.path().file_name().ok_or(InitGenesisError::Missing)?;
let fpath = dir_path.join(fname);

let default_content = file.contents();
std::fs::create_dir_all(dir_path).map_err(|e| {
InitGenesisError::DirNotCreated { path: dir_path.to_path_buf(), cause: e }
})?;

std::fs::write(&fpath, default_content)
.map_err(|e| InitGenesisError::FileNotWritten { path: fpath, cause: e })
}
26 changes: 23 additions & 3 deletions kindelia/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
mod cli;
mod config;
mod files;
mod genesis;
mod util;

use std::future::Future;
Expand Down Expand Up @@ -38,6 +39,7 @@ use util::{
};

use crate::cli::{GetStatsKind, NodeCleanBlocksCommand, NodeCleanCommand};
use crate::genesis::{genesis_code, init_genesis};
use crate::util::init_config_file;

fn main() -> Result<(), String> {
Expand Down Expand Up @@ -245,6 +247,8 @@ pub fn run_cli() -> Result<(), String> {
let path = default_config_path()?;
eprintln!("Writing default configuration to '{}'...", path.display());
init_config_file(&path)?;
init_genesis(&default_base_path()?.join("genesis"))
.map_err(|e| e.to_string())?;
Ok(())
}
CliCommand::Node { command, data_dir, network_id } => {
Expand Down Expand Up @@ -552,12 +556,18 @@ pub fn sign_code(
Ok(stat)
}

fn load_code(file: FileInput, encoded: bool) -> Result<Vec<ast::Statement>, String> {
fn load_code(
file: FileInput,
encoded: bool,
) -> Result<Vec<ast::Statement>, String> {
let code = file.read_to_string()?;
handle_code(&code, encoded)
}

fn handle_code(code: &str, encoded: bool) -> Result<Vec<ast::Statement>, String> {
fn handle_code(
code: &str,
encoded: bool,
) -> Result<Vec<ast::Statement>, String> {
if encoded {
statements_from_hex_seq(code)
} else {
Expand Down Expand Up @@ -664,7 +674,11 @@ async fn join_all(
}

pub fn test_code(network_id: u32, code: &str, sudo: bool) {
hvm::test_statements_from_code(network_id, code, sudo);
let genesis_stmts =
parser::parse_code(&genesis_code(network_id).expect("Genesis code loads"))
.expect("Genesis code parses");

hvm::test_statements_from_code(&genesis_stmts, code, sudo);
}

fn init_socket() -> Option<UdpSocket> {
Expand Down Expand Up @@ -837,10 +851,16 @@ pub fn start_node<C: ProtoComm + 'static>(
// File writter
let file_writter = SimpleFileStorage::new(node_config.data_path.clone());

let genesis_stmts = parser::parse_code(
&genesis_code(node_config.network_id).expect("Genesis code loads"),
)
.expect("Genesis code parses");

// Node state object
let (node_query_sender, node) = Node::new(
node_config.data_path,
node_config.network_id,
&genesis_stmts,
initial_peers,
comm,
miner_comm,
Expand Down
2 changes: 1 addition & 1 deletion kindelia/tests/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ mod cli {
#[case("../example/block_3.kdl")]
#[case("../example/block_4.kdl")]
#[case("../example/block_5.kdl")]
#[case("../kindelia_core/genesis.kdl")]
#[case("../kindelia_core/genesis-tests.kdl")]
fn test_ser_deser(#[case] file: &str) {
use kindelia_core::bits::ProtoSerialize;
eprintln!("{}", file);
Expand Down
7 changes: 4 additions & 3 deletions kindelia_core/benches/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use kindelia_lang::parser;
use primitive_types::U256;

use kindelia_core::bits::ProtoSerialize;
use kindelia_core::{constants, hvm, net, node, util};
use kindelia_core::{hvm, net, node, util};

// KHVM
// ====
Expand All @@ -24,8 +24,9 @@ pub fn temp_dir() -> PathBuf {
}

pub fn init_runtime(path: PathBuf) -> hvm::Runtime {
const GENESIS_CODE: &str = include_str!("../genesis-tests.kdl");
let genesis_stmts =
parser::parse_code(constants::GENESIS_CODE).expect("Genesis code parses.");
parser::parse_code(GENESIS_CODE).expect("Genesis code parses.");
hvm::init_runtime(path, &genesis_stmts)
}

Expand Down Expand Up @@ -153,7 +154,7 @@ fn block_loading(c: &mut Criterion) {

// create Node
let (_, mut node) =
node::Node::new(dir.clone(), 0, vec![], comm, None, storage, None);
node::Node::new(dir.clone(), 0, &vec![], vec![], comm, None, storage, None);

// benchmark block loading
c.bench_function("block_loading", |b| b.iter(|| node.load_blocks()));
Expand Down
Loading

0 comments on commit f6435eb

Please sign in to comment.