diff --git a/data_model/src/parameter.rs b/data_model/src/parameter.rs index 4bc47bea3c2..66e1fd4f9b3 100644 --- a/data_model/src/parameter.rs +++ b/data_model/src/parameter.rs @@ -7,7 +7,6 @@ use std::collections::btree_map; use iroha_data_model_derive::model; use iroha_primitives::json::JsonString; -use nonzero_ext::nonzero; pub use self::model::*; use crate::{name::Name, Identifiable}; @@ -17,6 +16,11 @@ pub(crate) type CustomParameters = btree_map::BTreeMap u64 { + 2_000 + } + pub const fn commit_time_ms() -> u64 { + 4_000 + } + pub const fn max_clock_drift_ms() -> u64 { + 1_000 + } + } + + pub mod block { + use core::num::NonZeroU64; + + use nonzero_ext::nonzero; + + /// Default value for [`Parameters::MaxTransactionsInBlock`] + pub const fn max_transactions() -> NonZeroU64 { + nonzero!(2_u64.pow(9)) + } + } + + pub mod transaction { + use core::num::NonZeroU64; + + use nonzero_ext::nonzero; + + pub const fn max_instructions() -> NonZeroU64 { + nonzero!(2_u64.pow(12)) + } + pub const fn smart_contract_size() -> NonZeroU64 { + nonzero!(4 * 2_u64.pow(20)) + } + } + + pub mod smart_contract { + use core::num::NonZeroU64; + + use nonzero_ext::nonzero; + + pub const fn fuel() -> NonZeroU64 { + nonzero!(55_000_000_u64) + } + pub const fn memory() -> NonZeroU64 { + nonzero!(55_000_000_u64) + } + } +} + impl Default for SumeragiParameters { fn default() -> Self { - pub const DEFAULT_BLOCK_TIME_MS: u64 = 2_000; - pub const DEFAULT_COMMIT_TIME_MS: u64 = 4_000; - pub const DEFAULT_MAX_CLOCK_DRIFT_MS: u64 = 1_000; - + use defaults::sumeragi::*; Self { - block_time_ms: DEFAULT_BLOCK_TIME_MS, - commit_time_ms: DEFAULT_COMMIT_TIME_MS, - max_clock_drift_ms: DEFAULT_MAX_CLOCK_DRIFT_MS, + block_time_ms: block_time_ms(), + commit_time_ms: commit_time_ms(), + max_clock_drift_ms: max_clock_drift_ms(), } } } impl Default for BlockParameters { fn default() -> Self { - /// Default value for [`Parameters::MaxTransactionsInBlock`] - pub const DEFAULT_TRANSACTIONS_IN_BLOCK: NonZeroU64 = nonzero!(2_u64.pow(9)); - - Self::new(DEFAULT_TRANSACTIONS_IN_BLOCK) + Self::new(defaults::block::max_transactions()) } } impl Default for TransactionParameters { fn default() -> Self { - const DEFAULT_INSTRUCTION_NUMBER: NonZeroU64 = nonzero!(2_u64.pow(12)); - const DEFAULT_SMART_CONTRACT_SIZE: NonZeroU64 = nonzero!(4 * 2_u64.pow(20)); - - Self::new(DEFAULT_INSTRUCTION_NUMBER, DEFAULT_SMART_CONTRACT_SIZE) + use defaults::transaction::*; + Self::new(max_instructions(), smart_contract_size()) } } impl Default for SmartContractParameters { fn default() -> Self { - const DEFAULT_FUEL: NonZeroU64 = nonzero!(55_000_000_u64); - const DEFAULT_MEMORY: NonZeroU64 = nonzero!(55_000_000_u64); - + use defaults::smart_contract::*; Self { - fuel: DEFAULT_FUEL, - memory: DEFAULT_MEMORY, + fuel: fuel(), + memory: memory(), } } } @@ -516,7 +571,9 @@ mod candidate { #[derive(Decode, Deserialize)] struct TransactionParametersCandidate { + #[serde(default = "defaults::transaction::max_instructions")] max_instructions: NonZeroU64, + #[serde(default = "defaults::transaction::smart_contract_size")] smart_contract_size: NonZeroU64, } @@ -527,6 +584,7 @@ mod candidate { #[derive(Decode, Deserialize)] struct BlockParametersCandidate { + #[serde(default = "super::defaults::block::max_transactions")] max_transactions: NonZeroU64, } @@ -538,7 +596,9 @@ mod candidate { #[derive(Decode, Deserialize)] struct SmartContractParametersCandidate { + #[serde(default = "super::defaults::smart_contract::fuel")] fuel: NonZeroU64, + #[serde(default = "super::defaults::smart_contract::memory")] memory: NonZeroU64, } diff --git a/defaults/genesis.json b/defaults/genesis.json index c96cd79dc16..0144f0eea7e 100644 --- a/defaults/genesis.json +++ b/defaults/genesis.json @@ -1,58 +1,28 @@ { "chain": "00000000-0000-0000-0000-000000000000", "executor": "./executor.wasm", - "parameters": [ - { - "Sumeragi": { - "BlockTimeMs": 2000 - } - }, - { - "Sumeragi": { - "CommitTimeMs": 4000 - } - }, - { - "Sumeragi": { - "MaxClockDriftMs": 1000 - } - }, - { - "Block": { - "MaxTransactions": 512 - } - }, - { - "Transaction": { - "MaxInstructions": 4096 - } - }, - { - "Transaction": { - "SmartContractSize": 4194304 - } - }, - { - "Executor": { - "Fuel": 55000000 - } - }, - { - "Executor": { - "Memory": 55000000 - } - }, - { - "SmartContract": { - "Fuel": 55000000 - } - }, - { - "SmartContract": { - "Memory": 55000000 - } + "parameters": { + "sumeragi": { + "block_time_ms": 2000, + "commit_time_ms": 4000, + "max_clock_drift_ms": 1000 + }, + "block": { + "max_transactions": 512 + }, + "transaction": { + "max_instructions": 4096, + "smart_contract_size": 4194304 + }, + "executor": { + "fuel": 55000000, + "memory": 55000000 + }, + "smart_contract": { + "fuel": 55000000, + "memory": 55000000 } - ], + }, "instructions": [ { "Register": { diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index e95b33d6e5c..96b0b05dbad 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -2727,6 +2727,9 @@ "Option>>": { "Option": "Option>" }, + "Option": { + "Option": "Parameters" + }, "Option": { "Option": "PeerId" }, @@ -3411,7 +3414,7 @@ }, { "name": "parameters", - "type": "Vec" + "type": "Option" }, { "name": "instructions", diff --git a/genesis/src/lib.rs b/genesis/src/lib.rs index 326db3050d3..73bef89294a 100644 --- a/genesis/src/lib.rs +++ b/genesis/src/lib.rs @@ -40,8 +40,8 @@ pub struct RawGenesisTransaction { /// Path to the [`Executor`] file executor: ExecutorPath, /// Parameters - #[serde(default)] - parameters: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + parameters: Option, instructions: Vec, /// Initial topology topology: Vec, @@ -104,13 +104,16 @@ impl RawGenesisTransaction { /// If executor couldn't be read from provided path 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, - self.parameters, + parameters, ); Ok(genesis) } @@ -284,7 +287,7 @@ impl GenesisBuilder { RawGenesisTransaction { instructions: self.instructions, executor: ExecutorPath(executor_file), - parameters: self.parameters, + parameters: convert_parameters(self.parameters), chain: chain_id, topology, } @@ -324,6 +327,51 @@ impl GenesisDomainBuilder { } } +fn convert_parameters(parameters: Vec) -> Option { + if parameters.is_empty() { + return None; + } + let mut result = Parameters::default(); + for parameter in parameters.into_iter() { + apply_parameter(&mut result, parameter); + } + Some(result) +} + +fn apply_parameter(parameters: &mut Parameters, parameter: Parameter) { + macro_rules! apply_parameter { + ($($container:ident($param:ident.$field:ident) => $single:ident::$variant:ident),* $(,)?) => { + match parameter { + $( + Parameter::$container(iroha_data_model::parameter::$single::$variant(next)) => { + parameters.$param.$field = next; + } + )* + Parameter::Custom(next) => { + parameters.custom.insert(next.id.clone(), next); + } + } + }; + } + + apply_parameter!( + Sumeragi(sumeragi.max_clock_drift_ms) => SumeragiParameter::MaxClockDriftMs, + Sumeragi(sumeragi.block_time_ms) => SumeragiParameter::BlockTimeMs, + Sumeragi(sumeragi.commit_time_ms) => SumeragiParameter::CommitTimeMs, + + Block(block.max_transactions) => BlockParameter::MaxTransactions, + + Transaction(transaction.max_instructions) => TransactionParameter::MaxInstructions, + Transaction(transaction.smart_contract_size) => TransactionParameter::SmartContractSize, + + SmartContract(smart_contract.fuel) => SmartContractParameter::Fuel, + SmartContract(smart_contract.memory) => SmartContractParameter::Memory, + + Executor(executor.fuel) => SmartContractParameter::Fuel, + Executor(executor.memory) => SmartContractParameter::Memory, + ); +} + impl Encode for ExecutorPath { fn encode(&self) -> Vec { self.0 @@ -484,4 +532,34 @@ mod tests { ); } } + + #[test] + fn genesis_parameters_deserialization() { + fn test(parameters: &str) { + let genesis_json = format!( + r#"{{ + "parameters": {}, + "chain": "0", + "executor": "./executor.wasm", + "topology": [], + "instructions": [] + }}"#, + parameters + ); + let _genesis: RawGenesisTransaction = + serde_json::from_str(&genesis_json).expect("Failed to deserialize"); + } + + // Empty parameters + test("{}"); + test( + r#"{"sumeragi": {}, "block": {}, "transaction": {}, "executor": {}, "smart_contract": {}}"#, + ); + + // Inner value missing + test(r#"{"sumeragi": {"block_time_ms": 2000}}"#); + test(r#"{"transaction": {"max_instructions": 4096}}"#); + test(r#"{"executor": {"fuel": 55000000}}"#); + test(r#"{"smart_contract": {"fuel": 55000000}}"#); + } } diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index 8eaab624d6a..df7edf9e3ac 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -315,6 +315,7 @@ types!( Option, Option, Option>, + Option, Option, Option, Option,