Skip to content

Commit

Permalink
feat(core): load genesis file by network id
Browse files Browse the repository at this point in the history
Addresses kindelia#243

Support for loading a different genesis block for each network.

The genesis block is loaded from a file whose path is the pattern:
~/.kindelia/genesis/<network-id>.kdl

Changes:

 core:
  * add util::genesis_path() with associated error enum
  * add util::genesis_code() with associated error enum
  * modify hvm::test_statements*() to accept network_id and load genesis
    block from file instead of compiled string
  * modify node::new() to to accept network_id and load genesis block
    from file instead of compiled string

 cli:
  * add network_id to test command, required by hvm::test_statements()
  * fix parsing of hex values for --network_id
  * add clap_num dep for parsing hex values
  • Loading branch information
dan-da committed Dec 3, 2022
1 parent 0b44aee commit 494c6b7
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 15 deletions.
1 change: 1 addition & 0 deletions kindelia/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ derive_builder = "0.11.2"
# CLI / configuration
clap = { version = "4.0.18", features = ["derive"] }
clap_complete = "4.0.3"
clap-num = "1.0.2"
toml = "0.5.9"

# Datastructures
Expand Down
6 changes: 5 additions & 1 deletion kindelia/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::path::PathBuf;

use clap::{Parser, Subcommand};
use clap_complete::Shell;
use clap_num::maybe_hex;

use kindelia_common::Name;
use kindelia_core::api::LimitStats;
Expand Down Expand Up @@ -120,6 +121,9 @@ pub enum CliCommand {
/// Whether to consider size and mana in the execution.
#[clap(long)]
sudo: bool,
/// Network id / magic number.
#[clap(long, value_parser=maybe_hex::<u32>)]
network_id: Option<u32>,
},
/// Checks for statements in kdl file
Check {
Expand Down Expand Up @@ -205,7 +209,7 @@ pub enum CliCommand {
#[clap(long)]
data_dir: Option<PathBuf>,
/// Network id / magic number.
#[clap(long)]
#[clap(long, value_parser=maybe_hex::<u32>)]
network_id: Option<u32>,
},
/// Generate auto-completion for a shell.
Expand Down
19 changes: 15 additions & 4 deletions kindelia/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,20 @@ pub fn run_cli() -> anyhow::Result<()> {
);

match parsed.command {
CliCommand::Test { file, sudo } => {
CliCommand::Test { file, sudo, network_id } => {
let config = handle_config_file(&config_path).map_err(|e| anyhow!(e))?;
let config = Some(&config);

let network_id = resolve_cfg!(
env = "KINDELIA_NETWORK_ID",
prop = "node.network.network_id".to_string(),
no_default = anyhow!("Missing `network_id` parameter."),
cli_val = network_id,
cfg = config,
);

let code: String = file.read_to_string()?;
test_code(&code, sudo);
test_code(network_id, &code, sudo);
Ok(())
}
CliCommand::Check { file, encoded, command } => {
Expand Down Expand Up @@ -655,8 +666,8 @@ async fn join_all(
Ok(())
}

pub fn test_code(code: &str, sudo: bool) {
runtime::test_statements_from_code(code, sudo);
pub fn test_code(network_id: u32, code: &str, sudo: bool) {
runtime::test_statements_from_code(network_id, code, sudo);
}

fn init_socket() -> Option<UdpSocket> {
Expand Down
3 changes: 1 addition & 2 deletions kindelia_core/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use crate::api::{BlockInfo, FuncInfo, NodeRequest};
use crate::bits;
use crate::bits::ProtoSerialize;
use crate::config::MineConfig;
use crate::constants;
use crate::net::{ProtoAddr, ProtoComm};
use crate::persistence::BlockStorage;
use crate::runtime::*;
Expand Down Expand Up @@ -776,7 +775,7 @@ impl<C: ProtoComm, S: BlockStorage> Node<C, S> {
let (query_sender, query_receiver) = mpsc::sync_channel(1);

let genesis_stmts =
parser::parse_code(constants::GENESIS_CODE).expect("Genesis code parses");
parser::parse_code(&genesis_code(network_id).unwrap()).expect("Genesis code parses");
let genesis_block = build_genesis_block(&genesis_stmts);
let genesis_block = genesis_block.hashed();
let genesis_hash = genesis_block.get_hash().into();
Expand Down
15 changes: 7 additions & 8 deletions kindelia_core/src/runtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,8 @@ use kindelia_lang::ast::{Func, Oper, Statement, Term, Var};
use kindelia_lang::parser::{parse_code, parse_statements, ParseErr};

use crate::bits::ProtoSerialize;
use crate::constants;
use crate::persistence::DiskSer;
use crate::util::{self, mask, U128_SIZE};
use crate::util::{self, genesis_code, mask, U128_SIZE};
use crate::util::{LocMap, NameMap, U120Map, U128Map};

// Functions
Expand Down Expand Up @@ -4227,7 +4226,7 @@ pub fn print_io_consts() {
}

// Serializes, deserializes and evaluates statements
pub fn test_statements(statements: &Vec<Statement>, debug: bool) {
pub fn test_statements(network_id: u32, statements: &Vec<Statement>, debug: bool) {
let str_0 = ast::view_statements(statements);
let statements = &Vec::proto_deserialized(&statements.proto_serialized()).unwrap();
let str_1 = ast::view_statements(statements);
Expand All @@ -4238,7 +4237,7 @@ pub fn test_statements(statements: &Vec<Statement>, debug: bool) {

// TODO: code below does not need heaps_path at all. extract heap persistence out of Runtime.
let heaps_path = dirs::home_dir().unwrap().join(".kindelia").join("state").join("heaps");
let genesis_smts = parse_code(constants::GENESIS_CODE).expect("Genesis code parses");
let genesis_smts = parse_code(&genesis_code(network_id).unwrap()).expect("Genesis code parses");
let mut rt = init_runtime(heaps_path, &genesis_smts);
let init = Instant::now();
rt.run_statements(&statements, false, debug);
Expand All @@ -4254,14 +4253,14 @@ pub fn test_statements(statements: &Vec<Statement>, debug: bool) {
println!("[time] {} ms", init.elapsed().as_millis());
}

pub fn test_statements_from_code(code: &str, debug: bool) {
pub fn test_statements_from_code(network_id: u32, code: &str, debug: bool) {
let statments = parse_statements(code);
match statments {
Ok((.., statements)) => test_statements(&statements, debug),
Ok((.., statements)) => test_statements(network_id, &statements, debug),
Err(ParseErr { code, erro }) => println!("{}", erro),
}
}

pub fn test_statements_from_file(file: &str, debug: bool) {
test_statements_from_code(&std::fs::read_to_string(file).expect("file not found"), debug);
pub fn test_statements_from_file(network_id: u32, file: &str, debug: bool) {
test_statements_from_code(network_id, &std::fs::read_to_string(file).expect("file not found"), debug);
}
35 changes: 35 additions & 0 deletions kindelia_core/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
// #![allow(clippy::style)]

use std::collections::HashMap;
use std::path::PathBuf;
use thiserror::Error;

use bit_vec::BitVec;

Expand Down Expand Up @@ -181,3 +183,36 @@ macro_rules! print_with_timestamp {
println!("{} ~~ {}", get_time_micro(), format!($($arg)*));
};
}

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

pub(crate) 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(crate) enum GenesisCodeError {
#[error(transparent)]
PathError(#[from] GenesisPathError),

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

pub(crate) 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})
}

0 comments on commit 494c6b7

Please sign in to comment.