From 3ea17e91cd13ede30788828630d9aaffd8aee63d Mon Sep 17 00:00:00 2001 From: VAmuzing Date: Fri, 5 Apr 2024 03:25:09 +0300 Subject: [PATCH] [fix] change how signed genesis is represented; minor fixes Signed-off-by: VAmuzing --- Cargo.lock | 1 + cli/src/lib.rs | 17 ++- client/examples/million_accounts_genesis.rs | 19 ++- config/src/parameters/actual.rs | 7 +- config/src/parameters/user.rs | 30 ++--- config/src/parameters/user/boilerplate.rs | 13 ++ config/tests/fixtures.rs | 6 +- .../fixtures/minimal_alone_with_genesis.toml | 1 + core/test_network/src/lib.rs | 4 +- data_model/src/transaction.rs | 23 ++++ genesis/Cargo.toml | 3 +- genesis/src/lib.rs | 120 ++++++++++++++---- hooks/pre-commit.sample | 4 +- scripts/test_env.py | 5 +- tools/kagami/src/crypto.rs | 89 +++++++------ tools/kagami/src/genesis.rs | 11 +- 16 files changed, 229 insertions(+), 124 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba3b0a33747..0b473a579e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3047,6 +3047,7 @@ version = "2.0.0-pre-rc.20" dependencies = [ "derive_more", "eyre", + "hex", "iroha_crypto", "iroha_data_model", "iroha_schema", diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 770d37039b3..bc4ebd583cc 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -6,7 +6,7 @@ //! should be constructed externally: (see `main.rs`). #[cfg(debug_assertions)] use core::sync::atomic::{AtomicBool, Ordering}; -use std::{fs, path::Path, sync::Arc}; +use std::{path::Path, sync::Arc}; use color_eyre::eyre::{eyre, Result, WrapErr}; use iroha_config::parameters::{actual::Root as Config, user::CliContext}; @@ -27,7 +27,7 @@ use iroha_core::{ IrohaNetwork, }; use iroha_data_model::prelude::*; -use iroha_genesis::GenesisNetwork; +use iroha_genesis::{GenesisNetwork, RawGenesisBlock, SignedGenesisConfig}; use iroha_logger::actor::LoggerHandle; use iroha_torii::Torii; use tokio::{ @@ -518,10 +518,17 @@ pub fn read_config_and_genesis>( let config = Config::load(path, CliContext { submit_genesis }) .wrap_err("failed to load configuration")?; - let genesis = if let Genesis::Full { public_key: _, file } = &config.genesis { - let signed_json_block = fs::read(file)?; + let genesis = if let Genesis::Full { + public_key: _, + file, + encoded_config: encoded_genesis_config, + } = &config.genesis + { + let raw_genesis = RawGenesisBlock::from_path(file)?; - Some(serde_json::from_slice(signed_json_block.as_slice())?) + let signed_genesis_config = SignedGenesisConfig::from_hex_string(encoded_genesis_config)?; + + Some(signed_genesis_config.validate(raw_genesis)?) } else { None }; diff --git a/client/examples/million_accounts_genesis.rs b/client/examples/million_accounts_genesis.rs index d8c2885f4e4..7a173f7d75a 100644 --- a/client/examples/million_accounts_genesis.rs +++ b/client/examples/million_accounts_genesis.rs @@ -31,11 +31,14 @@ fn generate_genesis(num_domains: u32) -> (RawGenesisBlock, KeyPair) { .finish_domain(); } - (builder - .executor_blob( - construct_executor("../default_executor").expect("Failed to construct executor"), - ) - .build(), key_pair) + ( + builder + .executor_blob( + construct_executor("../default_executor").expect("Failed to construct executor"), + ) + .build(), + key_pair, + ) } fn main_genesis() { @@ -49,11 +52,7 @@ fn main_genesis() { ); let rt = Runtime::test(); let (genesis, key_pair) = generate_genesis(1_000_000_u32); - let genesis = GenesisNetwork::new( - genesis, - &chain_id, - &key_pair - ); + let genesis = GenesisNetwork::new(genesis, &chain_id, &key_pair); let builder = PeerBuilder::new() .with_into_genesis(genesis) diff --git a/config/src/parameters/actual.rs b/config/src/parameters/actual.rs index 96334324211..5aa6770ec8b 100644 --- a/config/src/parameters/actual.rs +++ b/config/src/parameters/actual.rs @@ -93,8 +93,10 @@ pub enum Genesis { Full { /// Genesis account public key public_key: PublicKey, - /// Path to the signed genesis block + /// Path to the genesis file file: PathBuf, + /// Hex-encoded genesis config + encoded_config: String, }, } @@ -102,8 +104,7 @@ impl Genesis { /// Access the public key, which is always present in the genesis config pub fn public_key(&self) -> &PublicKey { match self { - Self::Partial { public_key } => public_key, - Self::Full { public_key, .. } => public_key, + Self::Full { public_key, .. } | Self::Partial { public_key } => public_key, } } } diff --git a/config/src/parameters/user.rs b/config/src/parameters/user.rs index 935f1a50e07..a9235b9b0be 100644 --- a/config/src/parameters/user.rs +++ b/config/src/parameters/user.rs @@ -309,43 +309,31 @@ pub(crate) fn private_key_from_env( pub struct Genesis { pub public_key: PublicKey, pub file: Option, + pub encoded_config: Option, } impl Genesis { - // fn parse(self, cli: CliContext) -> actual::Genesis { - // match self.file { - // None => actual::Genesis::Partial { - // public_key: self.public_key, - // }, - // Some(file) => actual::Genesis::Full { - // public_key: self.public_key, - // file, - // }, - // // (Some(_), Some(_), false) => Err(GenesisConfigError::GenesisWithoutSubmit), - // // (None, None, true) => Err(GenesisConfigError::SubmitWithoutGenesis), - // // _ => Err(GenesisConfigError::Inconsistent), - // } - // } fn parse(self, cli: CliContext) -> Result { - match (self.file, cli.submit_genesis) { - (None, false) => Ok(actual::Genesis::Partial { + match (self.file, self.encoded_config, cli.submit_genesis) { + (None, None, false) => Ok(actual::Genesis::Partial { public_key: self.public_key, }), - (Some(file), true) => Ok(actual::Genesis::Full { + (Some(file), Some(encoded_config), true) => Ok(actual::Genesis::Full { public_key: self.public_key, file, + encoded_config, }), - (Some(_), false) => Err(GenesisConfigError::GenesisWithoutSubmit), - (None, true) => Err(GenesisConfigError::SubmitWithoutGenesis), + (_, _, false) => Err(GenesisConfigError::GenesisWithoutSubmit), + (_, _, true) => Err(GenesisConfigError::SubmitWithoutGenesis), } } } -#[derive(Debug, displaydoc::Display, thiserror::Error)] +#[derive(Copy, Clone, Debug, displaydoc::Display, thiserror::Error)] pub enum GenesisConfigError { /// `genesis.file` and `genesis.public_key` are presented, but `--submit-genesis` was not set GenesisWithoutSubmit, - /// `--submit-genesis` was set, but `genesis.file` and `genesis.public_key` are not presented + /// `--submit-genesis` was set, but `genesis.file`, `genesis.public_key` and `genesis.encoded_config` are not presented SubmitWithoutGenesis, } diff --git a/config/src/parameters/user/boilerplate.rs b/config/src/parameters/user/boilerplate.rs index b84d7d0179f..53af50d526d 100644 --- a/config/src/parameters/user/boilerplate.rs +++ b/config/src/parameters/user/boilerplate.rs @@ -185,6 +185,7 @@ impl FromEnv for RootPartial { pub struct GenesisPartial { pub public_key: UserField, pub file: UserField, + pub encoded_config: UserField, } impl UnwrapPartial for GenesisPartial { @@ -198,9 +199,12 @@ impl UnwrapPartial for GenesisPartial { let file = self.file.get(); + let encoded_config = self.encoded_config.get(); + Ok(Genesis { public_key, file, + encoded_config, }) } } @@ -223,11 +227,20 @@ impl FromEnv for GenesisPartial { let file = ParseEnvResult::parse_simple(&mut emitter, env, "GENESIS_FILE", "genesis.file").into(); + let encoded_config = ParseEnvResult::parse_simple( + &mut emitter, + env, + "ENCODED_CONFIG", + "genesis.encoded_config", + ) + .into(); + emitter.finish()?; Ok(Self { public_key, file, + encoded_config, }) } } diff --git a/config/tests/fixtures.rs b/config/tests/fixtures.rs index a9c3c6949a7..33bd4cc0710 100644 --- a/config/tests/fixtures.rs +++ b/config/tests/fixtures.rs @@ -9,7 +9,7 @@ use std::{ use eyre::Result; use iroha_config::parameters::{ actual::{Genesis, Root}, - user::RootPartial, + user::{CliContext, RootPartial}, }; use iroha_config_base::{FromEnv, TestEnv, UnwrapPartial as _}; @@ -183,9 +183,7 @@ fn config_with_genesis() -> Result<()> { Ok(()) } -// TODO: Verify #[test] -#[ignore = "--submit-genesis was removed, more in #4225"] fn minimal_with_genesis_but_no_cli_arg_fails() -> Result<()> { let error = RootPartial::from_toml(fixtures_dir().join("minimal_alone_with_genesis.toml"))? .unwrap_partial()? @@ -203,7 +201,6 @@ fn minimal_with_genesis_but_no_cli_arg_fails() -> Result<()> { } #[test] -#[ignore = "--submit-genesis was removed, more in #4225"] fn minimal_without_genesis_but_with_submit_fails() -> Result<()> { let error = RootPartial::from_toml(fixtures_dir().join("minimal_with_trusted_peers.toml"))? .unwrap_partial()? @@ -264,7 +261,6 @@ fn extra_fields() { } #[test] -#[ignore = "temporarily, more in #4225"] fn inconsistent_genesis_config() -> Result<()> { let error = RootPartial::from_toml(fixtures_dir().join("inconsistent_genesis.toml"))? .unwrap_partial() diff --git a/config/tests/fixtures/minimal_alone_with_genesis.toml b/config/tests/fixtures/minimal_alone_with_genesis.toml index 8b886c8b8f5..03028d7ca4c 100644 --- a/config/tests/fixtures/minimal_alone_with_genesis.toml +++ b/config/tests/fixtures/minimal_alone_with_genesis.toml @@ -3,3 +3,4 @@ extends = "base.toml" [genesis] file = "./empty_ok_genesis.json" public_key = "ed01208BA62848CF767D72E7F7F4B9D2D7BA07FEE33760F79ABE5597A51520E292A0CB" +encoded_config = "9030303030303030302d303030302d303030302d303030302d303030303030303030303030ea9933ab8e0100000400804c390aef5d919d5506756ac51f7dd7e768da13fa60413fd5dc136851e9117213010145dd0ec90d6982851cdac085b54085a0e78689f14844742dcfc7da15b6ef78055584658cad5b9d69da200fa3997e490bfea2d7c417be9f6221d5ca89ba650008" diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 7fb272d8dff..f83b1052704 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -120,11 +120,11 @@ impl TestGenesis for GenesisNetwork { upgrade_executor_permission, ] { first_transaction - .append_instruction(Grant::permission(permission, alice_id.clone()).into()); + .push_instruction(Grant::permission(permission, alice_id.clone()).into()); } for isi in extra_isi.into_iter() { - first_transaction.append_instruction(isi); + first_transaction.push_instruction(isi); } GenesisNetwork::new( diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index fbfded831ab..81ab787e0b2 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -326,6 +326,29 @@ impl SignedTransaction { } } +#[cfg(feature = "transparent_api")] +impl TryFrom<(SignaturesOf, TransactionPayload)> for SignedTransaction { + type Error = &'static str; + + fn try_from( + value: (SignaturesOf, TransactionPayload), + ) -> Result { + let (signatures, payload) = value; + if let Executable::Instructions(isi) = &payload.instructions { + if isi.is_empty() { + return Err("Transaction is empty"); + } + } + signatures + .verify(&payload) + .map_err(|_| "Transaction contains invalid signatures")?; + Ok(SignedTransaction::V1(SignedTransactionV1 { + signatures, + payload, + })) + } +} + #[cfg(feature = "transparent_api")] impl From for (AccountId, Executable) { fn from(source: SignedTransaction) -> Self { diff --git a/genesis/Cargo.toml b/genesis/Cargo.toml index f53dfb4b180..ecdf054bd42 100644 --- a/genesis/Cargo.toml +++ b/genesis/Cargo.toml @@ -12,7 +12,7 @@ workspace = true [dependencies] iroha_crypto = { workspace = true } -iroha_data_model = { workspace = true, features = ["http"] } +iroha_data_model = { workspace = true, features = ["http", "transparent_api"] } iroha_schema = { workspace = true } parity-scale-codec = { workspace = true, features = ["derive"] } @@ -22,6 +22,7 @@ serde_json = { workspace = true } once_cell = { workspace = true } tracing = { workspace = true } eyre = { workspace = true } +hex = { workspace = true } [dev-dependencies] iroha_crypto = { workspace = true, features = ["rand"] } diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index 32ba38684b6..54ecf9ec7e2 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -9,12 +9,16 @@ use std::{ }; use eyre::{eyre, Report, Result, WrapErr}; -use iroha_crypto::{KeyPair, PublicKey}; +use iroha_crypto::{KeyPair, PublicKey, SignaturesOf}; use iroha_data_model::{ - asset::{AssetDefinition, AssetValueType}, executor::Executor, prelude::{Metadata, *}, ChainId + asset::{AssetDefinition, AssetValueType}, + executor::Executor, + prelude::{Metadata, *}, + transaction::TransactionPayload, + ChainId, }; -use parity_scale_codec::{Decode, Encode}; use once_cell::sync::Lazy; +use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; /// [`DomainId`] of the genesis account. @@ -29,6 +33,75 @@ pub static GENESIS_ACCOUNT_ID: Lazy = #[repr(transparent)] pub struct GenesisTransaction(pub SignedTransaction); +impl GenesisTransaction { + /// Construct single genesis transaction with [`Executor`] and transactions unified under a single transaction + pub fn new_unified( + raw_block: RawGenesisBlock, + chain_id: &ChainId, + genesis_key_pair: &KeyPair, + ) -> GenesisTransaction { + Self(raw_block.unify().sign(chain_id.clone(), genesis_key_pair)) + } +} + +/// [`SignedGenesisConfig`] contains data that is used for loading signed genesis from config. +#[derive(Debug, Clone, Deserialize, Serialize, Decode, Encode)] +pub struct SignedGenesisConfig { + chain_id: ChainId, + creation_time_ms: u64, + signatures: SignaturesOf, +} + +impl SignedGenesisConfig { + /// Create [`SignedGenesisConfig`] from it's components + pub fn new( + chain_id: ChainId, + creation_time_ms: u64, + signatures: SignaturesOf, + ) -> Self { + Self { + chain_id, + creation_time_ms, + signatures, + } + } + + /// Checks that [`SignedGenesisConfig`] corresponds to [`RawGenesisBlock`] and produces [`GenesisNetwork`] if it does. + /// # Errors + /// Fails if [`RawGenesisBlock`] does not correspond to [`SignedGenesisConfig`] and it was unable to verify it's integrity + pub fn validate(self, genesis_block: RawGenesisBlock) -> Result { + let payload = TransactionPayload { + chain_id: self.chain_id, + creation_time_ms: self.creation_time_ms, + authority: GENESIS_ACCOUNT_ID.clone(), + instructions: Executable::Instructions(genesis_block.unify().isi), + time_to_live_ms: None, + nonce: None, + metadata: UnlimitedMetadata::new(), + }; + + let tmp = SignedTransaction::try_from((self.signatures, payload)) + .map_err(|_| eyre!("Failed to"))?; + Ok(GenesisNetwork { + transactions: Vec::from([GenesisTransaction(tmp)]), + }) + } + + /// Serialize self to hex string + pub fn to_hex_string(&self) -> String { + hex::encode(self.encode()) + } + + /// Deserialize [`SignedGenesisConfig`] from hex representation + /// # Errors + /// Fails if it cannot either decode hex string or decode scale-encoded bytes + pub fn from_hex_string>(hex: &S) -> Result { + let decoded_hex = hex::decode(hex).map_err(|_| eyre!("Failed to decode hex string"))?; + Decode::decode(&mut decoded_hex.as_slice()) + .map_err(|_| eyre!("Failed to decode scale-encoded data")) + } +} + /// [`GenesisNetwork`] contains initial transactions and genesis setup related parameters. #[derive(Debug, Clone, Decode, Encode, Deserialize, Serialize)] pub struct GenesisNetwork { @@ -43,32 +116,13 @@ impl GenesisNetwork { raw_block: RawGenesisBlock, chain_id: &ChainId, genesis_key_pair: &KeyPair, - ) -> GenesisNetwork { - Self::new_with_executor_and_txs(raw_block.executor, raw_block.transactions, chain_id, genesis_key_pair) - } - - /// Construct from configuration with only [`Executor`] from genesis block - pub fn new_without_transactions( - raw_block: RawGenesisBlock, - chain_id: &ChainId, - genesis_key_pair: &KeyPair, - ) -> GenesisNetwork { - Self::new_with_executor_and_txs(raw_block.executor, Vec::new(), chain_id, genesis_key_pair) - } - - /// Construct from configuration with explicit separation between [`Executor`] and transactions - fn new_with_executor_and_txs( - executor: Executor, - transactions: Vec, - chain_id: &ChainId, - genesis_key_pair: &KeyPair, ) -> GenesisNetwork { // The first instruction should be Executor upgrade. // This makes it possible to grant permissions to users in genesis. let transactions_iter = std::iter::once(GenesisTransactionBuilder { - isi: vec![Upgrade::new(executor).into()], + isi: vec![Upgrade::new(raw_block.executor).into()], }) - .chain(transactions); + .chain(raw_block.transactions); let transactions = transactions_iter .map(|raw_transaction| raw_transaction.sign(chain_id.clone(), genesis_key_pair)) @@ -103,6 +157,14 @@ impl RawGenesisBlock { pub fn from_path>(path: P) -> Result { RawGenesisBlockFile::from_path(path)?.try_into() } + + fn unify(self) -> GenesisTransactionBuilder { + let mut unified_tx = GenesisTransactionBuilder { + isi: vec![Upgrade::new(self.executor).into()], + }; + unified_tx.extend_instructions(self.transactions.iter().flat_map(|v| v.isi.clone())); + unified_tx + } } /// A (de-)serializable version of [`RawGenesisBlock`]. @@ -190,9 +252,17 @@ impl GenesisTransactionBuilder { } /// Add new instruction to the transaction. - pub fn append_instruction(&mut self, instruction: InstructionBox) { + pub fn push_instruction(&mut self, instruction: InstructionBox) { self.isi.push(instruction); } + + /// Add new instructions to the transaction + pub fn extend_instructions(&mut self, iter: I) + where + I: IntoIterator, + { + self.isi.extend(iter) + } } /// Builder type for [`RawGenesisBlock`] that does diff --git a/hooks/pre-commit.sample b/hooks/pre-commit.sample index cb2ec5d9621..a06dbfdf7d7 100755 --- a/hooks/pre-commit.sample +++ b/hooks/pre-commit.sample @@ -5,5 +5,5 @@ cargo +nightly lints clippy --workspace --benches --tests --examples --all-featu cargo run --bin kagami -- genesis >configs/swarm/genesis.json cargo run --bin kagami -- schema >docs/source/references/schema.json cargo run --bin kagami -- crypto generate-key-pair -j >configs/swarm/keypair.json -cargo run --bin kagami -- crypto sign-transaction --keypair-file configs/swarm/keypair.json --genesis-file configs/swarm/genesis.json --chain-id 00000000-0000-0000-0000-000000000000 --out-file configs/swarm/signed_genesis.json -git add configs/peer/genesis.json configs/swarm/keypair.json configs/swarm/signed_genesis.json docs/source/references/schema.json +cargo run --bin kagami -- crypto sign-transaction --keypair-file configs/swarm/keypair.json --genesis-file configs/swarm/genesis.json --chain-id 00000000-0000-0000-0000-000000000000 --out-file configs/swarm/signed_genesis.txt +git add configs/peer/genesis.json configs/swarm/keypair.json configs/swarm/signed_genesis.txt docs/source/references/schema.json diff --git a/scripts/test_env.py b/scripts/test_env.py index 770855f714f..28f7d1382bd 100755 --- a/scripts/test_env.py +++ b/scripts/test_env.py @@ -148,7 +148,7 @@ def __init__(self, args: argparse.Namespace, nth: int): sys.exit(1) sign_command = [self.out_dir / "kagami", "crypto", "sign-transaction", "--chain-id", CHAIN_ID, - "--genesis-file", self.peer_dir / "./genesis.json", "--out-file", self.peer_dir/ "./signed_genesis.json", + "--genesis-file", self.peer_dir / "./genesis.json", "-a", self.private_key["algorithm"], "--private-key-string", self.private_key["payload"], "--public-key-string", self.public_key] @@ -161,7 +161,8 @@ def __init__(self, args: argparse.Namespace, nth: int): config["genesis"] = { "public_key": self.public_key, - "file": "./signed_genesis.json" + "file": "./genesis.json", + "encoded_config": kagami_genesis.stdout.decode("utf-8").rstrip('\n'), } with open(self.config_path, "wb") as f: diff --git a/tools/kagami/src/crypto.rs b/tools/kagami/src/crypto.rs index 29f7d30f5de..67c0f41761c 100644 --- a/tools/kagami/src/crypto.rs +++ b/tools/kagami/src/crypto.rs @@ -10,7 +10,7 @@ use color_eyre::{ }; use iroha_crypto::{Algorithm, KeyPair, PrivateKey}; use iroha_data_model::ChainId; -use iroha_genesis::{GenesisNetwork, RawGenesisBlock}; +use iroha_genesis::{GenesisTransaction, RawGenesisBlock, SignedGenesisConfig}; use parity_scale_codec::Encode; use super::*; @@ -53,9 +53,9 @@ pub struct SignGenesisArgs { /// Path to genesis json file #[clap(long, short)] genesis_file: PathBuf, - /// Output signed genesis block in JSON format - #[clap(long, short, default_value_t = true, group = "format")] - json: bool, + /// Output signed genesis config as a hex string + #[clap(long, default_value_t = true, group = "format")] + hex: bool, /// Encode signed genesis block with SCALE (it is only supported with file output) #[clap(long, short, default_value_t = false, group = "format")] scale: bool, @@ -151,26 +151,32 @@ impl RunArgs for SignGenesisArgs { }; let genesis_block = RawGenesisBlock::from_path(&self.genesis_file)?; - let genesis_network = GenesisNetwork::new_without_transactions(genesis_block, &self.chain_id, &key_pair); + let genesis_tx = + GenesisTransaction::new_unified(genesis_block, &self.chain_id, &key_pair).0; + let signed_genesis_config = SignedGenesisConfig::new( + genesis_tx.chain_id().clone(), + genesis_tx.creation_time().as_millis().try_into()?, + genesis_tx.signatures().clone(), + ) + .to_hex_string(); - let encoded_genesis_network = if self.scale { - genesis_network.encode() + let encoded_genesis_config = if self.scale { + signed_genesis_config.encode() } else { Vec::default() }; - let json_genesis_network = if self.json { - serde_json::to_string_pretty(&genesis_network) - .wrap_err("Failed to serialise genesis network to JSON.")? + let hex_genesis_config = if self.hex { + signed_genesis_config } else { String::default() }; if let Some(path) = self.out_file { if self.scale { - fs::write(&path, encoded_genesis_network)?; + fs::write(&path, encoded_genesis_config)?; } else { - fs::write(&path, json_genesis_network)?; + fs::write(&path, hex_genesis_config)?; } writeln!( @@ -184,7 +190,7 @@ impl RunArgs for SignGenesisArgs { "SCALE encoded data is not supported for console outputs." )?; } else { - writeln!(writer, "{json_genesis_network}")?; + writeln!(writer, "{hex_genesis_config}")?; } Ok(()) @@ -290,7 +296,6 @@ impl GenerateKeyPairArgs { #[cfg(test)] mod tests { // use iroha_data_model::transaction::{SignedTransactionV1, TransactionPayload}; - use parity_scale_codec::Decode; use super::*; @@ -304,8 +309,6 @@ mod tests { const GENESIS_JSON_PATH: &str = "../../configs/swarm/genesis.json"; const GEN_KEYPAIR_JSON_PATH: &str = "test_keypair_path_for_crypt0_genesis_kagami.json"; - const GEN_SIGNED_ENCODED_GENESIS_PATH: &str = - "test_signed_encoded_genesis_path_for_crypt0_genesis_kagami"; fn genesis_signing_works() -> Result { let keypair_config = GenerateKeyPairArgs { @@ -332,45 +335,47 @@ mod tests { keypair_file: Some(PathBuf::from_str(GEN_KEYPAIR_JSON_PATH)?), chain_id: chain_id.clone(), genesis_file: PathBuf::from_str(GENESIS_JSON_PATH)?, - out_file: Some(PathBuf::from_str(GEN_SIGNED_ENCODED_GENESIS_PATH)?), - scale: true, - json: false, + out_file: None, + scale: false, + hex: true, }; let mut genesis_buf_writer = BufWriter::new(Vec::new()); crypto_genesis_config.run(&mut genesis_buf_writer)?; + let mut encoded_genesis_config = genesis_buf_writer.buffer().to_owned(); + encoded_genesis_config.pop(); + + let decoded_signed_genesis_config = + SignedGenesisConfig::from_hex_string(&encoded_genesis_config)?; + let raw_genesis = RawGenesisBlock::from_path(GENESIS_JSON_PATH)?; - let signed_genesis_manually = GenesisNetwork::new(raw_genesis, &chain_id, &keypair); - - let signed_genesis_from_file_encoded = fs::read(GEN_SIGNED_ENCODED_GENESIS_PATH)?; - let maybe_signed_genesis_from_file: GenesisNetwork = - GenesisNetwork::decode(&mut signed_genesis_from_file_encoded.as_slice())?; - - Ok(signed_genesis_manually - .into_transactions() - .into_iter() - .zip( - maybe_signed_genesis_from_file - .into_transactions(), - ) - .all(|(a, b)| { - a.0.metadata() == b.0.metadata() - && a.0.authority() == b.0.authority() - && a.0.chain_id() == b.0.chain_id() - && a.0.time_to_live() == b.0.time_to_live() - && a.0.instructions() == b.0.instructions() - && a.0.nonce() == b.0.nonce() - && a.0.signatures() == b.0.signatures() - })) + let signed_genesis_manually = + GenesisTransaction::new_unified(raw_genesis.clone(), &chain_id, &keypair); + let signed_genesis_from_config = &decoded_signed_genesis_config + .validate(raw_genesis)? + .into_transactions()[0]; + + let cmp = |a: &SignedTransaction, b: &SignedTransaction| { + a.metadata() == b.metadata() + && a.authority() == b.authority() + && a.chain_id() == b.chain_id() + && a.time_to_live() == b.time_to_live() + && a.instructions() == b.instructions() + && a.nonce() == b.nonce() + && a.signatures() == b.signatures() + }; + Ok(cmp( + &signed_genesis_from_config.0, + &signed_genesis_manually.0, + )) } #[test] fn test_genesis_signing_works() { let result = genesis_signing_works(); let _ = fs::remove_file(GEN_KEYPAIR_JSON_PATH); - let _ = fs::remove_file(GEN_SIGNED_ENCODED_GENESIS_PATH); assert!(result.is_ok_and(|result| result)); } } diff --git a/tools/kagami/src/genesis.rs b/tools/kagami/src/genesis.rs index 94c851f0e91..4d070b2a874 100644 --- a/tools/kagami/src/genesis.rs +++ b/tools/kagami/src/genesis.rs @@ -182,7 +182,7 @@ pub fn generate_default( .chain(parameter_defaults.into_iter()) .chain(std::iter::once(register_user_metadata_access)) { - first_tx.append_instruction(isi); + first_tx.push_instruction(isi); } Ok(genesis) @@ -203,13 +203,12 @@ fn generate_synthetic( for domain in 0..domains { let domain_id: DomainId = format!("domain_{domain}").parse()?; - first_transaction - .append_instruction(Register::domain(Domain::new(domain_id.clone())).into()); + first_transaction.push_instruction(Register::domain(Domain::new(domain_id.clone())).into()); for account in 0..accounts_per_domain { let (public_key, _) = iroha_crypto::KeyPair::random().into_parts(); let account_id: AccountId = format!("account_{account}@{domain_id}").parse()?; - first_transaction.append_instruction( + first_transaction.push_instruction( Register::account(Account::new(account_id.clone(), public_key)).into(), ); } @@ -217,7 +216,7 @@ fn generate_synthetic( for asset in 0..assets_per_domain { let asset_definition_id: AssetDefinitionId = format!("asset_{asset}#{domain_id}").parse()?; - first_transaction.append_instruction( + first_transaction.push_instruction( Register::asset_definition(AssetDefinition::new( asset_definition_id, AssetValueType::Numeric(NumericSpec::default()), @@ -240,7 +239,7 @@ fn generate_synthetic( ), ) .into(); - first_transaction.append_instruction(mint); + first_transaction.push_instruction(mint); } } }