diff --git a/kindelia/Cargo.toml b/kindelia/Cargo.toml index 798b9ec..7c9639a 100644 --- a/kindelia/Cargo.toml +++ b/kindelia/Cargo.toml @@ -35,6 +35,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 diff --git a/kindelia/src/cli.rs b/kindelia/src/cli.rs index bdf3c82..f3d6166 100644 --- a/kindelia/src/cli.rs +++ b/kindelia/src/cli.rs @@ -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; @@ -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::)] + network_id: Option, }, /// Checks for statements in kdl file Check { @@ -205,7 +209,7 @@ pub enum CliCommand { #[clap(long)] data_dir: Option, /// Network id / magic number. - #[clap(long)] + #[clap(long, value_parser=maybe_hex::)] network_id: Option, }, /// Generate auto-completion for a shell. diff --git a/kindelia/src/main.rs b/kindelia/src/main.rs index edfb50c..eca233d 100644 --- a/kindelia/src/main.rs +++ b/kindelia/src/main.rs @@ -125,9 +125,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 } => { @@ -664,8 +675,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 { diff --git a/kindelia_core/src/node.rs b/kindelia_core/src/node.rs index 2f3e834..20e5d0a 100644 --- a/kindelia_core/src/node.rs +++ b/kindelia_core/src/node.rs @@ -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, BlockStorageError}; use crate::runtime::*; @@ -783,7 +782,7 @@ impl Node { 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(); diff --git a/kindelia_core/src/runtime/mod.rs b/kindelia_core/src/runtime/mod.rs index f190c58..14ad04a 100644 --- a/kindelia_core/src/runtime/mod.rs +++ b/kindelia_core/src/runtime/mod.rs @@ -113,10 +113,9 @@ use kindelia_lang::ast::{Oper, Statement, Term}; use kindelia_lang::parser::{parse_code, parse_statements, ParseErr}; use crate::bits::ProtoSerialize; -use crate::constants; use crate::persistence::DiskSer; use crate::runtime::functions::compile_func; -use crate::util::{self, U128_SIZE}; +use crate::util::{self, genesis_code, U128_SIZE}; use crate::util::{LocMap, NameMap, U120Map, U128Map}; pub use memory::{CellTag, RawCell, Loc}; @@ -3218,7 +3217,7 @@ pub fn print_io_consts() { } // Serializes, deserializes and evaluates statements -pub fn test_statements(statements: &Vec, debug: bool) { +pub fn test_statements(network_id: u32, statements: &Vec, 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); @@ -3229,7 +3228,7 @@ pub fn test_statements(statements: &Vec, 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); @@ -3245,14 +3244,14 @@ pub fn test_statements(statements: &Vec, 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); } diff --git a/kindelia_core/src/util.rs b/kindelia_core/src/util.rs index 7239371..393198f 100644 --- a/kindelia_core/src/util.rs +++ b/kindelia_core/src/util.rs @@ -5,6 +5,7 @@ // #![allow(clippy::style)] use std::collections::HashMap; +use std::path::PathBuf; use bit_vec::BitVec; @@ -13,7 +14,6 @@ use kindelia_common::{Name, U120, U256}; use std::time::{SystemTime, SystemTimeError, UNIX_EPOCH}; use crate::runtime::Loc; -use std::path::PathBuf; use thiserror::Error; @@ -244,3 +244,40 @@ pub struct FileSystemError { pub context: String, pub source: std::io::Error, } + + +// Genesis +// ======= + +#[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 { + 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 { + let path = genesis_path(network_id)?; + std::fs::read_to_string(&path).map_err(|e| GenesisCodeError::ReadError{path, cause: e}) +}