diff --git a/bindings/ergo-lib-c-core/src/parameters.rs b/bindings/ergo-lib-c-core/src/parameters.rs index a2d011206..2bc7ca566 100644 --- a/bindings/ergo-lib-c-core/src/parameters.rs +++ b/bindings/ergo-lib-c-core/src/parameters.rs @@ -1,4 +1,7 @@ //! Ergo blockchain state (for ErgoTree evaluation) + +use crate::util::mut_ptr_as_mut; +use crate::Error; use ergo_lib::chain; /// Blockchain parameters @@ -14,6 +17,17 @@ pub unsafe fn parameters_default(parameters_out: *mut ParametersPtr) { ))); } +/// Parse parameters from JSON. Supports Ergo Node API/Explorer API +pub unsafe fn parameters_from_json( + json: &str, + parameters_out: *mut ParametersPtr, +) -> Result<(), Error> { + let parameters_out = mut_ptr_as_mut(parameters_out, "parameters_out")?; + let parameters = serde_json::from_str(json).map(Parameters)?; + *parameters_out = Box::into_raw(Box::new(parameters)); + Ok(()) +} + pub unsafe fn parameters_delete(parameters: ParametersPtr) { if !parameters.is_null() { let boxed = Box::from_raw(parameters); diff --git a/bindings/ergo-lib-c/src/parameters.rs b/bindings/ergo-lib-c/src/parameters.rs index 1e55e659f..02459ca9a 100644 --- a/bindings/ergo-lib-c/src/parameters.rs +++ b/bindings/ergo-lib-c/src/parameters.rs @@ -1,6 +1,9 @@ -use ergo_lib_c_core::parameters::{parameters_default, ParametersPtr}; +use ergo_lib_c_core::parameters::{parameters_default, parameters_from_json, ParametersPtr}; +use ergo_lib_c_core::Error; +use std::ffi::CStr; +use std::os::raw::c_char; -use crate::delete_ptr; +use crate::{delete_ptr, ErrorPtr}; /// Return default blockchain parameters that were set at genesis #[no_mangle] @@ -8,6 +11,17 @@ pub unsafe extern "C" fn ergo_lib_parameters_default(parameters_out: *mut Parame parameters_default(parameters_out); } +/// Parse parameters from JSON. Supports Ergo Node API/Explorer API +#[no_mangle] +pub unsafe extern "C" fn ergo_lib_parameters_from_json( + json_str: *const c_char, + parameters_out: *mut ParametersPtr, +) -> ErrorPtr { + let json = CStr::from_ptr(json_str).to_string_lossy(); + let res = parameters_from_json(&json, parameters_out); + Error::c_api_from(res) +} + #[no_mangle] pub unsafe extern "C" fn ergo_lib_parameters_delete(parameters: ParametersPtr) { delete_ptr(parameters) diff --git a/ergo-lib/src/chain/json.rs b/ergo-lib/src/chain/json.rs index cdb7b11f1..211832f14 100644 --- a/ergo-lib/src/chain/json.rs +++ b/ergo-lib/src/chain/json.rs @@ -6,6 +6,7 @@ use ergotree_interpreter::sigma_protocol::prover::ProofBytes; pub(crate) mod context_extension; pub(crate) mod hint; +pub(crate) mod parameters; pub(crate) mod transaction; /// Serde remote type diff --git a/ergo-lib/src/chain/json/parameters.rs b/ergo-lib/src/chain/json/parameters.rs new file mode 100644 index 000000000..db4873d63 --- /dev/null +++ b/ergo-lib/src/chain/json/parameters.rs @@ -0,0 +1,101 @@ +use crate::chain::parameters::{Parameter, Parameters}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone)] +pub struct ParametersJson { + #[cfg_attr(feature = "json", serde(rename = "blockVersion"))] + pub block_version: i32, + #[cfg_attr(feature = "json", serde(rename = "storageFeeFactor"))] + pub storage_fee_factor: i32, + #[cfg_attr(feature = "json", serde(rename = "minValuePerByte"))] + pub min_value_per_byte: i32, + #[cfg_attr(feature = "json", serde(rename = "maxBlockSize"))] + pub max_block_size: i32, + #[cfg_attr(feature = "json", serde(rename = "maxBlockCost"))] + pub max_block_cost: i32, + #[cfg_attr(feature = "json", serde(rename = "tokenAccessCost"))] + pub token_access_cost: i32, + #[cfg_attr(feature = "json", serde(rename = "inputCost"))] + pub input_cost: i32, + #[cfg_attr(feature = "json", serde(rename = "dataInputCost"))] + pub data_input_cost: i32, + #[cfg_attr(feature = "json", serde(rename = "outputCost"))] + pub output_cost: i32, +} + +impl From for Parameters { + fn from(v: ParametersJson) -> Self { + let mut parameters_table = HashMap::new(); + parameters_table.insert(Parameter::StorageFeeFactor, v.storage_fee_factor); + parameters_table.insert(Parameter::MinValuePerByte, v.min_value_per_byte); + parameters_table.insert(Parameter::TokenAccessCost, v.token_access_cost); + parameters_table.insert(Parameter::InputCost, v.input_cost); + parameters_table.insert(Parameter::DataInputCost, v.data_input_cost); + parameters_table.insert(Parameter::OutputCost, v.output_cost); + parameters_table.insert(Parameter::MaxBlockSize, v.max_block_size); + parameters_table.insert(Parameter::BlockVersion, v.block_version); + Self { parameters_table } + } +} + +#[cfg(test)] +#[allow(clippy::unwrap_used)] +mod tests { + use crate::chain::parameters::Parameters; + + #[test] + fn parse_parameters() { + let node_info_json = r#" +{ + "currentTime": 1715205595940, + "network": "mainnet", + "name": "ergo-mainnet-5.0.21", + "stateType": "utxo", + "difficulty": 1540866762080256, + "bestFullHeaderId": "e1b3f8333afc89155e212774866f8751e44971cf1516e12f805f1585bc0d66ef", + "bestHeaderId": "e1b3f8333afc89155e212774866f8751e44971cf1516e12f805f1585bc0d66ef", + "peersCount": 139, + "unconfirmedCount": 13, + "appVersion": "5.0.21", + "eip37Supported": true, + "stateRoot": "d3d071999ea4f44a6fe530caf1770f16fb0b6c15a1d25eda58046817290da0311a", + "genesisBlockId": "b0244dfc267baca974a4caee06120321562784303a8a688976ae56170e4d175b", + "previousFullHeaderId": "5764b1402c42c770918ee61c000ea3bf46434c1f8d3d767e824f62cbbf0c15b8", + "fullHeight": 1260242, + "headersHeight": 1260242, + "stateVersion": "e1b3f8333afc89155e212774866f8751e44971cf1516e12f805f1585bc0d66ef", + "fullBlocksScore": 2311302610372215701504, + "maxPeerHeight": 1260242, + "launchTime": 1714213167701, + "isExplorer": true, + "lastSeenMessageTime": 1715205582525, + "eip27Supported": true, + "headersScore": 2311302610372215701504, + "parameters": { + "outputCost": 194, + "tokenAccessCost": 100, + "maxBlockCost": 8001091, + "height": 1259520, + "maxBlockSize": 1271009, + "dataInputCost": 100, + "blockVersion": 3, + "inputCost": 2407, + "storageFeeFactor": 1250000, + "minValuePerByte": 360 + }, + "isMining": true +} + "#; + let params: Parameters = serde_json::from_str(node_info_json).unwrap(); + assert_eq!(params.output_cost(), 194); + assert_eq!(params.token_access_cost(), 100); + assert_eq!(params.max_block_cost(), 8001091); + assert_eq!(params.max_block_size(), 1271009); + assert_eq!(params.data_input_cost(), 100); + assert_eq!(params.block_version(), 3); + assert_eq!(params.input_cost(), 2407); + assert_eq!(params.storage_fee_factor(), 1250000); + assert_eq!(params.min_value_per_byte(), 360); + } +} diff --git a/ergo-lib/src/chain/parameters.rs b/ergo-lib/src/chain/parameters.rs index c71c59915..87c91ee8f 100644 --- a/ergo-lib/src/chain/parameters.rs +++ b/ergo-lib/src/chain/parameters.rs @@ -27,9 +27,15 @@ pub enum Parameter { } /// System parameters which can be adjusted via soft-fork +#[cfg_attr(feature = "json", derive(serde::Deserialize))] +#[cfg_attr( + feature = "json", + serde(try_from = "crate::chain::json::parameters::ParametersJson") +)] #[derive(Clone, Debug, Eq, PartialEq)] pub struct Parameters { - parameters_table: HashMap, + /// table of adjustable system parameters + pub parameters_table: HashMap, } impl Parameters {