From aa4d60bf8e53fc5e9d73e4e4cfecd999e258e97f Mon Sep 17 00:00:00 2001 From: Shunkichi Sato <49983831+s8sato@users.noreply.github.com> Date: Fri, 25 Oct 2024 16:30:59 +0900 Subject: [PATCH] refactor: streamline `GenesisBuilder` `RawGenesisTransaction` `GenesisBlock` flow (#5191) Signed-off-by: Shunkichi Sato <49983831+s8sato@users.noreply.github.com> --- Cargo.lock | 1 + crates/iroha_core/src/kura.rs | 18 +- crates/iroha_data_model/src/parameter.rs | 9 + crates/iroha_genesis/Cargo.toml | 2 + crates/iroha_genesis/src/lib.rs | 391 ++++++++++---------- crates/iroha_kagami/src/genesis/generate.rs | 30 +- crates/iroha_kagami/src/genesis/sign.rs | 9 +- crates/iroha_test_network/src/config.rs | 12 +- crates/irohad/src/main.rs | 27 +- 9 files changed, 264 insertions(+), 235 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21dc980e338..850a3a1bb87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3308,6 +3308,7 @@ dependencies = [ "parity-scale-codec", "serde", "serde_json", + "tempfile", ] [[package]] diff --git a/crates/iroha_core/src/kura.rs b/crates/iroha_core/src/kura.rs index b2251b9c773..0c5f7fefe2d 100644 --- a/crates/iroha_core/src/kura.rs +++ b/crates/iroha_core/src/kura.rs @@ -817,10 +817,9 @@ mod tests { use iroha_data_model::{ account::Account, domain::{Domain, DomainId}, - executor::Executor, isi::Log, peer::PeerId, - transaction::{TransactionBuilder, WasmSmartContract}, + transaction::TransactionBuilder, ChainId, Level, }; use iroha_genesis::GenesisBuilder; @@ -1111,16 +1110,11 @@ mod tests { live_query_store, ); - let executor = { - let executor_blob = std::fs::read("../../defaults/executor.wasm").unwrap(); - Executor::new(WasmSmartContract::from_compiled(executor_blob)) - }; - let genesis = GenesisBuilder::default().build_and_sign( - chain_id.clone(), - executor, - topology.as_ref().to_owned(), - &genesis_key_pair, - ); + let executor_path = PathBuf::from("../../defaults/executor.wasm").into(); + let genesis = GenesisBuilder::new(chain_id.clone(), executor_path) + .set_topology(topology.as_ref().to_owned()) + .build_and_sign(&genesis_key_pair) + .expect("genesis block should be built"); { let mut state_block = state.block(genesis.0.header()); diff --git a/crates/iroha_data_model/src/parameter.rs b/crates/iroha_data_model/src/parameter.rs index ff04c6a520b..b90a4e7ff27 100644 --- a/crates/iroha_data_model/src/parameter.rs +++ b/crates/iroha_data_model/src/parameter.rs @@ -443,6 +443,15 @@ impl Default for SmartContractParameters { } } +impl FromIterator for Parameters { + fn from_iter>(iter: T) -> Self { + iter.into_iter().fold(Parameters::default(), |mut acc, x| { + acc.set_parameter(x); + acc + }) + } +} + impl Parameters { /// Convert [`Self`] into iterator of individual parameters pub fn parameters(&self) -> impl Iterator + '_ { diff --git a/crates/iroha_genesis/Cargo.toml b/crates/iroha_genesis/Cargo.toml index 55905983f6b..3167e2d7975 100644 --- a/crates/iroha_genesis/Cargo.toml +++ b/crates/iroha_genesis/Cargo.toml @@ -24,3 +24,5 @@ parity-scale-codec = { workspace = true } [dev-dependencies] iroha_crypto = { workspace = true, features = ["rand"] } iroha_test_samples = { workspace = true } + +tempfile = { workspace = true } diff --git a/crates/iroha_genesis/src/lib.rs b/crates/iroha_genesis/src/lib.rs index 70649c91ebd..ad9b899e76c 100644 --- a/crates/iroha_genesis/src/lib.rs +++ b/crates/iroha_genesis/src/lib.rs @@ -10,9 +10,7 @@ use std::{ use eyre::{eyre, Result, WrapErr}; use iroha_crypto::{KeyPair, PublicKey}; -use iroha_data_model::{ - block::SignedBlock, isi::Instruction, parameter::Parameter, peer::Peer, prelude::*, -}; +use iroha_data_model::{block::SignedBlock, parameter::Parameter, peer::Peer, prelude::*}; use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; @@ -23,8 +21,7 @@ pub static GENESIS_DOMAIN_ID: LazyLock = LazyLock::new(|| "genesis".pa /// Genesis block. /// /// First transaction must contain single [`Upgrade`] instruction to set executor. -/// Second transaction must contain all other instructions. -/// If there are no other instructions, second transaction will be omitted. +/// Subsequent transactions can be parameter settings, instructions, topology change, in this order if they exist. #[derive(Debug, Clone)] #[repr(transparent)] pub struct GenesisBlock(pub SignedBlock); @@ -55,14 +52,22 @@ pub struct ExecutorPath(PathBuf); impl RawGenesisTransaction { const WARN_ON_GENESIS_GTE: u64 = 1024 * 1024 * 1024; // 1Gb - /// Construct a genesis block from a `.json` file at the specified - /// path-like object. + /// Construct [`RawGenesisTransaction`] from a json file at `json_path`, + /// resolving relative paths to `json_path`. /// /// # Errors - /// If file not found or deserialization from file fails. - pub fn from_path>(path: P) -> Result { - let file = File::open(&path) - .wrap_err_with(|| eyre!("failed to open genesis at {}", path.as_ref().display()))?; + /// + /// - file not found + /// - metadata access to the file failed + /// - deserialization failed + pub fn from_path(json_path: impl AsRef) -> Result { + let here = json_path + .as_ref() + .parent() + .expect("json file should be in some directory"); + let file = File::open(&json_path).wrap_err_with(|| { + eyre!("failed to open genesis at {}", json_path.as_ref().display()) + })?; let size = file .metadata() .wrap_err("failed to access genesis file metadata")? @@ -71,168 +76,146 @@ impl RawGenesisTransaction { eprintln!("Genesis is quite large, it will take some time to process it (size = {}, threshold = {})", size, Self::WARN_ON_GENESIS_GTE); } let reader = BufReader::new(file); + let mut value: Self = serde_json::from_reader(reader).wrap_err_with(|| { eyre!( "failed to deserialize raw genesis block from {}", - path.as_ref().display() + json_path.as_ref().display() ) })?; - value.executor = ExecutorPath( - path.as_ref() - .parent() - .expect("genesis must be a file in some directory") - .join(value.executor.0), - ); + + value.executor.resolve(here); + Ok(value) } - /// Add new instruction to the genesis block. - pub fn append_instruction(&mut self, instruction: impl Instruction) { - self.instructions.push(instruction.into()); - } + /// Revert to builder to add modifications. + pub fn into_builder(self) -> GenesisBuilder { + let parameters = self + .parameters + .map_or(Vec::new(), |parameters| parameters.parameters().collect()); - /// Change topology - #[must_use] - pub fn with_topology(mut self, topology: Vec) -> Self { - self.topology = topology; - self + GenesisBuilder { + chain: self.chain, + executor: self.executor, + instructions: self.instructions, + parameters, + topology: self.topology, + } } /// Build and sign genesis block. /// /// # Errors - /// If executor couldn't be read from provided path + /// + /// Fails if [`RawGenesisTransaction::parse`] fails. pub fn build_and_sign(self, genesis_key_pair: &KeyPair) -> Result { - let executor = get_executor(&self.executor.0)?; - let parameters = self - .parameters - .map_or(Vec::new(), |parameters| parameters.parameters().collect()); - let genesis = build_and_sign_genesis( - self.instructions, - executor, - self.chain, - genesis_key_pair, - self.topology, - parameters, - ); - Ok(genesis) + let chain = self.chain.clone(); + let mut transactions = vec![]; + for instructions in self.parse()? { + let transaction = build_transaction(instructions, chain.clone(), genesis_key_pair); + transactions.push(transaction); + } + let block = SignedBlock::genesis(transactions, genesis_key_pair.private_key()); + + Ok(GenesisBlock(block)) } -} -fn build_and_sign_genesis( - instructions: Vec, - executor: Executor, - chain_id: ChainId, - genesis_key_pair: &KeyPair, - topology: Vec, - parameters: Vec, -) -> GenesisBlock { - let transactions = build_transactions( - instructions, - executor, - parameters, - topology, - chain_id, - genesis_key_pair, - ); - let block = SignedBlock::genesis(transactions, genesis_key_pair.private_key()); - GenesisBlock(block) -} + /// Parse [`RawGenesisTransaction`] to the list of source instructions of the genesis transactions + /// + /// # Errors + /// + /// Fails if `self.executor` path fails to load [`Executor`]. + fn parse(self) -> Result>> { + let mut instructions_list = vec![]; -fn build_transactions( - instructions: Vec, - executor: Executor, - parameters: Vec, - topology: Vec, - chain_id: ChainId, - genesis_key_pair: &KeyPair, -) -> Vec { - let upgrade_isi = Upgrade::new(executor).into(); - let transaction_executor = - build_transaction(vec![upgrade_isi], chain_id.clone(), genesis_key_pair); - let mut transactions = vec![transaction_executor]; - if !topology.is_empty() { - let register_peers = build_transaction( - topology + let upgrade_executor = Upgrade::new(self.executor.try_into()?).into(); + instructions_list.push(vec![upgrade_executor]); + + if let Some(parameters) = self.parameters { + let instructions = parameters + .parameters() + .map(SetParameter::new) + .map(InstructionBox::from) + .collect(); + instructions_list.push(instructions); + } + + if !self.instructions.is_empty() { + instructions_list.push(self.instructions); + } + + if !self.topology.is_empty() { + let instructions = self + .topology .into_iter() .map(Peer::new) .map(Register::peer) .map(InstructionBox::from) - .collect(), - chain_id.clone(), - genesis_key_pair, - ); - transactions.push(register_peers) - } - if !parameters.is_empty() { - let parameters = build_transaction( - parameters - .into_iter() - .map(SetParameter::new) - .map(InstructionBox::from) - .collect(), - chain_id.clone(), - genesis_key_pair, - ); - transactions.push(parameters); - } - if !instructions.is_empty() { - let transaction_instructions = build_transaction(instructions, chain_id, genesis_key_pair); - transactions.push(transaction_instructions); + .collect(); + instructions_list.push(instructions) + } + + Ok(instructions_list) } - transactions } +/// Build a transaction and sign as the genesis account. fn build_transaction( instructions: Vec, - chain_id: ChainId, + chain: ChainId, genesis_key_pair: &KeyPair, ) -> SignedTransaction { - let genesis_account_id = AccountId::new( + let genesis_account = AccountId::new( GENESIS_DOMAIN_ID.clone(), genesis_key_pair.public_key().clone(), ); - TransactionBuilder::new(chain_id, genesis_account_id) + + TransactionBuilder::new(chain, genesis_account) .with_instructions(instructions) .sign(genesis_key_pair.private_key()) } -fn get_executor(file: &Path) -> Result { - let wasm = fs::read(file) - .wrap_err_with(|| eyre!("failed to read the executor from {}", file.display()))?; - Ok(Executor::new(WasmSmartContract::from_compiled(wasm))) -} - -/// Builder type for [`GenesisBlock`]/[`RawGenesisTransaction`]. -/// -/// that does not perform any correctness checking on the block produced. -/// Use with caution in tests and other things to register domains and accounts. +/// Builder to build [`RawGenesisTransaction`] and [`GenesisBlock`]. +/// No guarantee of validity of the built genesis transactions and block. #[must_use] -#[derive(Default)] pub struct GenesisBuilder { + chain: ChainId, + executor: ExecutorPath, instructions: Vec, parameters: Vec, + topology: Vec, } -/// `Domain` subsection of the [`GenesisBuilder`]. Makes -/// it easier to create accounts and assets without needing to -/// provide a `DomainId`. +/// Domain editing mode of the [`GenesisBuilder`] to register accounts and assets under the domain. #[must_use] pub struct GenesisDomainBuilder { - instructions: Vec, + chain: ChainId, + executor: ExecutorPath, parameters: Vec, + instructions: Vec, + topology: Vec, domain_id: DomainId, } impl GenesisBuilder { - /// Create a domain and return a domain builder which can - /// be used to create assets and accounts. + /// Construct [`GenesisBuilder`]. + pub fn new(chain: ChainId, executor: ExecutorPath) -> Self { + Self { + chain, + executor, + parameters: Vec::new(), + instructions: Vec::new(), + topology: Vec::new(), + } + } + + /// Entry a domain registration and transition to [`GenesisDomainBuilder`]. pub fn domain(self, domain_name: Name) -> GenesisDomainBuilder { self.domain_with_metadata(domain_name, Metadata::default()) } - /// Create a domain and return a domain builder which can - /// be used to create assets and accounts. + /// Same as [`GenesisBuilder::domain`], but attach a metadata to the domain. pub fn domain_with_metadata( mut self, domain_name: Name, @@ -240,72 +223,74 @@ impl GenesisBuilder { ) -> GenesisDomainBuilder { let domain_id = DomainId::new(domain_name); let new_domain = Domain::new(domain_id.clone()).with_metadata(metadata); + self.instructions.push(Register::domain(new_domain).into()); + GenesisDomainBuilder { - instructions: self.instructions, + chain: self.chain, + executor: self.executor, parameters: self.parameters, + instructions: self.instructions, + topology: self.topology, domain_id, } } - /// Add instruction to the end of genesis transaction + /// Entry a parameter setting to the end of entries. + pub fn append_parameter(mut self, parameter: Parameter) -> Self { + self.parameters.push(parameter); + self + } + + /// Entry a instruction to the end of entries. pub fn append_instruction(mut self, instruction: impl Into) -> Self { self.instructions.push(instruction.into()); self } - /// Add parameter to the end of parameter list - pub fn append_parameter(mut self, parameter: Parameter) -> Self { - self.parameters.push(parameter); + /// Overwrite the initial topology. + pub fn set_topology(mut self, topology: Vec) -> Self { + self.topology = topology; self } /// Finish building, sign, and produce a [`GenesisBlock`]. - pub fn build_and_sign( - self, - chain_id: ChainId, - executor_blob: Executor, - topology: Vec, - genesis_key_pair: &KeyPair, - ) -> GenesisBlock { - build_and_sign_genesis( - self.instructions, - executor_blob, - chain_id, - genesis_key_pair, - topology, - self.parameters, - ) + /// + /// # Errors + /// + /// Fails if internal [`RawGenesisTransaction::build_and_sign`] fails. + pub fn build_and_sign(self, genesis_key_pair: &KeyPair) -> Result { + self.build_raw().build_and_sign(genesis_key_pair) } /// Finish building and produce a [`RawGenesisTransaction`]. - pub fn build_raw( - self, - chain_id: ChainId, - executor_file: PathBuf, - topology: Vec, - ) -> RawGenesisTransaction { + pub fn build_raw(self) -> RawGenesisTransaction { + let parameters = + (!self.parameters.is_empty()).then(|| self.parameters.into_iter().collect()); + RawGenesisTransaction { + chain: self.chain, + executor: self.executor, + parameters, instructions: self.instructions, - executor: ExecutorPath(executor_file), - parameters: convert_parameters(self.parameters), - chain: chain_id, - topology, + topology: self.topology, } } } impl GenesisDomainBuilder { - /// Finish this domain and return to - /// genesis block building. + /// Finish this domain and return to genesis block building. pub fn finish_domain(self) -> GenesisBuilder { GenesisBuilder { - instructions: self.instructions, + chain: self.chain, + executor: self.executor, parameters: self.parameters, + instructions: self.instructions, + topology: self.topology, } } - /// Add an account to this domain + /// Add an account to this domain. pub fn account(self, signatory: PublicKey) -> Self { self.account_with_metadata(signatory, Metadata::default()) } @@ -318,7 +303,7 @@ impl GenesisDomainBuilder { self } - /// Add [`AssetDefinition`] to current domain. + /// Add [`AssetDefinition`] to this domain. pub fn asset(mut self, asset_name: Name, asset_type: AssetType) -> Self { let asset_definition_id = AssetDefinitionId::new(self.domain_id.clone(), asset_name); let asset_definition = AssetDefinition::new(asset_definition_id, asset_type); @@ -328,18 +313,6 @@ impl GenesisDomainBuilder { } } -fn convert_parameters(parameters: Vec) -> Option { - if parameters.is_empty() { - return None; - } - let mut result = Parameters::default(); - for parameter in parameters { - result.set_parameter(parameter); - } - - Some(result) -} - impl Encode for ExecutorPath { fn encode(&self) -> Vec { self.0 @@ -357,33 +330,74 @@ impl Decode for ExecutorPath { } } +impl From for ExecutorPath { + fn from(value: PathBuf) -> Self { + Self(value) + } +} + +impl TryFrom for Executor { + type Error = eyre::Report; + + fn try_from(value: ExecutorPath) -> Result { + let wasm = fs::read(&value.0) + .wrap_err_with(|| eyre!("failed to read the executor from {}", value.0.display()))?; + + Ok(Executor::new(WasmSmartContract::from_compiled(wasm))) + } +} + +impl ExecutorPath { + /// Resolve `self` to `here/self`, + /// assuming `self` is an unresolved relative path to `here`. + /// Must be applied once. + fn resolve(&mut self, here: impl AsRef) { + self.0 = here.as_ref().join(&self.0) + } +} + #[cfg(test)] mod tests { use iroha_test_samples::{ALICE_KEYPAIR, BOB_KEYPAIR}; + use tempfile::TempDir; use super::*; - fn dummy_executor() -> Executor { - Executor::new(WasmSmartContract::from_compiled(vec![1, 2, 3])) + fn dummy_executor() -> (TempDir, ExecutorPath) { + let tmp_dir = TempDir::new().unwrap(); + let wasm = WasmSmartContract::from_compiled(vec![1, 2, 3]); + let executor_path = tmp_dir.path().join("executor.wasm"); + std::fs::write(&executor_path, wasm).unwrap(); + + (tmp_dir, executor_path.into()) + } + + fn test_builder() -> (TempDir, GenesisBuilder) { + let (tmp_dir, executor_path) = dummy_executor(); + let chain = ChainId::from("00000000-0000-0000-0000-000000000000"); + let builder = GenesisBuilder::new(chain, executor_path); + + (tmp_dir, builder) } #[test] fn load_new_genesis_block() -> Result<()> { - let chain_id = ChainId::from("00000000-0000-0000-0000-000000000000"); let genesis_key_pair = KeyPair::random(); let (alice_public_key, _) = KeyPair::random().into_parts(); + let (_tmp_dir, builder) = test_builder(); - let _genesis_block = GenesisBuilder::default() + let _genesis_block = builder .domain("wonderland".parse()?) .account(alice_public_key) .finish_domain() - .build_and_sign(chain_id, dummy_executor(), vec![], &genesis_key_pair); + .build_and_sign(&genesis_key_pair)?; + Ok(()) } #[test] #[allow(clippy::too_many_lines)] - fn genesis_block_builder_example() { + fn genesis_block_builder_example() -> Result<()> { let public_key: std::collections::HashMap<&'static str, PublicKey> = [ ("alice", ALICE_KEYPAIR.public_key().clone()), ("bob", BOB_KEYPAIR.public_key().clone()), @@ -392,7 +406,8 @@ mod tests { ] .into_iter() .collect(); - let mut genesis_builder = GenesisBuilder::default(); + let (_tmp_dir, mut genesis_builder) = test_builder(); + let executor_path = genesis_builder.executor.clone(); genesis_builder = genesis_builder .domain("wonderland".parse().unwrap()) @@ -411,30 +426,28 @@ mod tests { .finish_domain(); // In real cases executor should be constructed from a wasm blob - let finished_genesis = genesis_builder.build_and_sign( - ChainId::from("00000000-0000-0000-0000-000000000000"), - dummy_executor(), - vec![], - &KeyPair::random(), - ); + let finished_genesis = genesis_builder.build_and_sign(&KeyPair::random())?; let transactions = &finished_genesis.0.transactions().collect::>(); // First transaction { let transaction = transactions[0]; - let instructions = transaction.value.instructions(); + let instructions = transaction.as_ref().instructions(); let Executable::Instructions(instructions) = instructions else { panic!("Expected instructions"); }; - assert_eq!(instructions[0], Upgrade::new(dummy_executor()).into()); + assert_eq!( + instructions[0], + Upgrade::new(executor_path.try_into()?).into() + ); assert_eq!(instructions.len(), 1); } // Second transaction let transaction = transactions[1]; - let instructions = transaction.value.instructions(); + let instructions = transaction.as_ref().instructions(); let Executable::Instructions(instructions) = instructions else { panic!("Expected instructions"); }; @@ -499,6 +512,8 @@ mod tests { .into() ); } + + Ok(()) } #[test] @@ -506,11 +521,11 @@ mod tests { fn test(parameters: &str) { let genesis_json = format!( r#"{{ - "parameters": {parameters}, - "chain": "0", - "executor": "./executor.wasm", - "topology": [], - "instructions": [] + "chain": "0", + "executor": "./executor.wasm", + "parameters": {parameters}, + "instructions": [], + "topology": [] }}"# ); diff --git a/crates/iroha_kagami/src/genesis/generate.rs b/crates/iroha_kagami/src/genesis/generate.rs index b0bc4601f88..07f58ec3f52 100644 --- a/crates/iroha_kagami/src/genesis/generate.rs +++ b/crates/iroha_kagami/src/genesis/generate.rs @@ -59,18 +59,16 @@ impl RunArgs for Args { mode, } = self; - let builder = GenesisBuilder::default(); + let chain = ChainId::from("00000000-0000-0000-0000-000000000000"); + let builder = GenesisBuilder::new(chain, executor_path_in_genesis.into()); let genesis = match mode.unwrap_or_default() { - Mode::Default => { - generate_default(builder, executor_path_in_genesis, genesis_public_key) - } + Mode::Default => generate_default(builder, genesis_public_key), Mode::Synthetic { domains, accounts_per_domain, assets_per_domain, } => generate_synthetic( builder, - executor_path_in_genesis, genesis_public_key, domains, accounts_per_domain, @@ -85,7 +83,6 @@ impl RunArgs for Args { #[allow(clippy::too_many_lines)] pub fn generate_default( builder: GenesisBuilder, - executor_path: PathBuf, genesis_public_key: PublicKey, ) -> color_eyre::Result { let genesis_account_id = AccountId::new(GENESIS_DOMAIN_ID.clone(), genesis_public_key); @@ -149,32 +146,28 @@ pub fn generate_default( builder = builder.append_instruction(isi); } - // Will be replaced with actual topology either in scripts/test_env.py or in iroha_swarm - let topology = vec![]; - let chain_id = ChainId::from("00000000-0000-0000-0000-000000000000"); - let genesis = builder.build_raw(chain_id, executor_path, topology); - Ok(genesis) + Ok(builder.build_raw()) } fn generate_synthetic( builder: GenesisBuilder, - executor_path: PathBuf, genesis_public_key: PublicKey, domains: u64, accounts_per_domain: u64, assets_per_domain: u64, ) -> color_eyre::Result { // Synthetic genesis is extension of default one - let mut genesis = generate_default(builder, executor_path, genesis_public_key)?; + let default_genesis = generate_default(builder, genesis_public_key)?; + let mut builder = default_genesis.into_builder(); for domain in 0..domains { let domain_id: DomainId = format!("domain_{domain}").parse()?; - genesis.append_instruction(Register::domain(Domain::new(domain_id.clone()))); + builder = builder.append_instruction(Register::domain(Domain::new(domain_id.clone()))); for asset in 0..assets_per_domain { let asset_definition_id: AssetDefinitionId = format!("asset_{asset}#{domain_id}").parse()?; - genesis.append_instruction(Register::asset_definition(AssetDefinition::new( + builder = builder.append_instruction(Register::asset_definition(AssetDefinition::new( asset_definition_id, AssetType::Numeric(NumericSpec::default()), ))); @@ -182,7 +175,8 @@ fn generate_synthetic( for _ in 0..accounts_per_domain { let (account_id, _account_keypair) = gen_account_in(&domain_id); - genesis.append_instruction(Register::account(Account::new(account_id.clone()))); + builder = + builder.append_instruction(Register::account(Account::new(account_id.clone()))); // FIXME: Should `assets_per_domain` be renamed to `asset_definitions_per_domain`? // https://github.com/hyperledger/iroha/issues/3508 @@ -194,10 +188,10 @@ fn generate_synthetic( account_id.clone(), ), ); - genesis.append_instruction(mint); + builder = builder.append_instruction(mint); } } } - Ok(genesis) + Ok(builder.build_raw()) } diff --git a/crates/iroha_kagami/src/genesis/sign.rs b/crates/iroha_kagami/src/genesis/sign.rs index 7e39025c33e..f7d89fa5c08 100644 --- a/crates/iroha_kagami/src/genesis/sign.rs +++ b/crates/iroha_kagami/src/genesis/sign.rs @@ -47,18 +47,19 @@ pub struct Args { impl RunArgs for Args { fn run(self, writer: &mut BufWriter) -> Outcome { let genesis_key_pair = self.get_key_pair()?; - let mut genesis = RawGenesisTransaction::from_path(&self.genesis_file)?; + let genesis = RawGenesisTransaction::from_path(&self.genesis_file)?; + let mut builder = genesis.into_builder(); if let Some(topology) = self.topology { let topology = serde_json::from_str(&topology).expect("Failed to parse topology"); - genesis = genesis.with_topology(topology); + builder = builder.set_topology(topology); } - let genesis_transaction = genesis.build_and_sign(&genesis_key_pair)?; + let genesis_block = builder.build_and_sign(&genesis_key_pair)?; let mut writer: Box = match self.out_file { None => Box::new(writer), Some(path) => Box::new(BufWriter::new(File::create(path)?)), }; - let bytes = genesis_transaction.0.encode(); + let bytes = genesis_block.0.encode(); writer.write_all(&bytes)?; Ok(()) diff --git a/crates/iroha_test_network/src/config.rs b/crates/iroha_test_network/src/config.rs index f1ad43bbbfe..17a2eb69e18 100644 --- a/crates/iroha_test_network/src/config.rs +++ b/crates/iroha_test_network/src/config.rs @@ -41,7 +41,7 @@ pub fn genesis( topology: UniqueVec, ) -> GenesisBlock { // TODO: Fix this somehow. Probably we need to make `kagami` a library (#3253). - let mut genesis = match RawGenesisTransaction::from_path( + let genesis = match RawGenesisTransaction::from_path( Path::new(env!("CARGO_MANIFEST_DIR")).join("../../defaults/genesis.json"), ) { Ok(x) => x, @@ -54,6 +54,7 @@ pub fn genesis( panic!("cannot proceed without genesis, see the error above"); } }; + let mut builder = genesis.into_builder(); let rose_definition_id = "rose#wonderland".parse::().unwrap(); let grant_modify_rose_permission = Grant::account_permission( @@ -79,16 +80,17 @@ pub fn genesis( grant_unregister_wonderland_domain, grant_upgrade_executor_permission, ] { - genesis.append_instruction(isi); + builder = builder.append_instruction(isi); } for isi in extra_isi { - genesis.append_instruction(isi); + builder = builder.append_instruction(isi); } let genesis_key_pair = SAMPLE_GENESIS_ACCOUNT_KEYPAIR.clone(); - genesis - .with_topology(topology.into()) + + builder + .set_topology(topology.into()) .build_and_sign(&genesis_key_pair) .expect("genesis should load fine") } diff --git a/crates/irohad/src/main.rs b/crates/irohad/src/main.rs index 45478a26e4e..1f265caa4cc 100644 --- a/crates/irohad/src/main.rs +++ b/crates/irohad/src/main.rs @@ -710,9 +710,11 @@ mod tests { mod config_integration { use assertables::{assert_contains, assert_contains_as_result}; use iroha_crypto::{ExposedPrivateKey, KeyPair}; + use iroha_genesis::ExecutorPath; use iroha_primitives::addr::socket_addr; use iroha_version::Encode; use path_absolutize::Absolutize as _; + use tempfile::TempDir; use super::*; @@ -730,8 +732,21 @@ mod tests { table } - fn dummy_executor() -> Executor { - Executor::new(WasmSmartContract::from_compiled(vec![1, 2, 3])) + fn dummy_executor() -> (TempDir, ExecutorPath) { + let tmp_dir = TempDir::new().unwrap(); + let wasm = WasmSmartContract::from_compiled(vec![1, 2, 3]); + let executor_path = tmp_dir.path().join("executor.wasm"); + std::fs::write(&executor_path, wasm).unwrap(); + + (tmp_dir, executor_path.into()) + } + + fn test_builder() -> (TempDir, GenesisBuilder) { + let (tmp_dir, executor_path) = dummy_executor(); + let chain = ChainId::from("00000000-0000-0000-0000-000000000000"); + let builder = GenesisBuilder::new(chain, executor_path); + + (tmp_dir, builder) } #[test] @@ -739,12 +754,8 @@ mod tests { // Given let genesis_key_pair = KeyPair::random(); - let genesis = GenesisBuilder::default().build_and_sign( - ChainId::from("00000000-0000-0000-0000-000000000000"), - dummy_executor(), - vec![], - &genesis_key_pair, - ); + let (_tmp_dir, builder) = test_builder(); + let genesis = builder.build_and_sign(&genesis_key_pair)?; let mut config = config_factory(genesis_key_pair.public_key()); iroha_config::base::toml::Writer::new(&mut config)