use crate::config::{CongestionControlConfig, WitnessConfig};
use crate::{ActionCosts, ExtCosts, Fee, ParameterCost, SignatureKind};
use near_account_id::AccountId;
use near_primitives_core::types::Balance;
use near_primitives_core::types::Gas;
use num_rational::Rational32;

/// View that preserves JSON format of the runtime config.
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct RuntimeConfigView {
    /// Amount of yN per byte required to have on the account.  See
    /// <https://nomicon.io/Economics/Economics.html#state-stake> for details.
    pub storage_amount_per_byte: Balance,
    /// Costs of different actions that need to be performed when sending and
    /// processing transaction and receipts.
    pub transaction_costs: RuntimeFeesConfigView,
    /// Config of wasm operations.
    pub wasm_config: VMConfigView,
    /// Config that defines rules for account creation.
    pub account_creation_config: AccountCreationConfigView,
    /// The configuration for congestion control.
    pub congestion_control_config: CongestionControlConfigView,
    /// Configuration specific to ChunkStateWitness.
    pub witness_config: WitnessConfigView,
    /// Minimum price at which the gas attached to a receipt is purchased. The price at which it is
    /// burned might be lower, in which case the difference is refunded after execution.
    #[serde(default)]
    pub min_gas_purchase_price: Balance,
    /// How much creating an account should cost in NEAR. Taken into account when burning gas for
    /// account creation.
    #[serde(default)]
    pub account_creation_charge: Balance,
}

/// Describes different fees for the runtime
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct RuntimeFeesConfigView {
    /// Describes the cost of creating an action receipt, `ActionReceipt`, excluding the actual cost
    /// of actions.
    /// - `send` cost is burned when a receipt is created using `promise_create` or
    ///     `promise_batch_create`
    /// - `exec` cost is burned when the receipt is being executed.
    pub action_receipt_creation_config: FeeView,
    /// Describes the cost of creating a data receipt, `DataReceipt`.
    pub data_receipt_creation_config: DataReceiptCreationConfigView,
    /// Describes the cost of creating a certain action, `Action`. Includes all variants.
    pub action_creation_config: ActionCreationConfigView,
    /// Describes fees for storage.
    pub storage_usage_config: StorageUsageConfigView,

    /// Fraction of the burnt gas to reward to the contract account for execution.
    #[cfg_attr(feature = "schemars", schemars(with = "Rational32SchemarsProvider"))]
    pub burnt_gas_reward: Rational32,

    /// Pessimistic gas price inflation ratio.
    #[cfg_attr(feature = "schemars", schemars(with = "Rational32SchemarsProvider"))]
    pub pessimistic_gas_price_inflation_ratio: Rational32,

    /// Describes the extra cost of verifying an ML-DSA-65 signature above the
    /// cost of verifying the standard signature types.
    pub ml_dsa_65_verification_cost: Gas,
}

/// The structure describes configuration for creation of new accounts.
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct AccountCreationConfigView {
    /// The minimum length of the top-level account ID that is allowed to be created by any account.
    pub min_allowed_top_level_account_length: u8,
    /// The account ID of the account registrar. This account ID allowed to create top-level
    /// accounts of any valid length.
    pub registrar_account_id: AccountId,
}

/// The fees settings for a data receipt creation
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct DataReceiptCreationConfigView {
    /// Base cost of creating a data receipt.
    /// Both `send` and `exec` costs are burned when a new receipt has input dependencies. The gas
    /// is charged for each input dependency. The dependencies are specified when a receipt is
    /// created using `promise_then` and `promise_batch_then`.
    /// NOTE: Any receipt with output dependencies will produce data receipts. Even if it fails.
    /// Even if the last action is not a function call (in case of success it will return empty
    /// value).
    pub base_cost: FeeView,
    /// Additional cost per byte sent.
    /// Both `send` and `exec` costs are burned when a function call finishes execution and returns
    /// `N` bytes of data to every output dependency. For each output dependency the cost is
    /// `(send(sir) + exec()) * N`.
    pub cost_per_byte: FeeView,
}

/// Describes the cost of creating a specific action, `Action`. Includes all variants.
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ActionCreationConfigView {
    /// Base cost of creating an account.
    pub create_account_cost: FeeView,

    /// Base cost of deploying a contract.
    pub deploy_contract_cost: FeeView,
    /// Cost per byte of deploying a contract.
    pub deploy_contract_cost_per_byte: FeeView,

    /// Base cost of calling a function.
    pub function_call_cost: FeeView,
    /// Cost per byte of method name and arguments of calling a function.
    pub function_call_cost_per_byte: FeeView,

    /// Base cost of making a transfer.
    pub transfer_cost: FeeView,

    /// Base cost of staking.
    pub stake_cost: FeeView,

    /// Base cost of adding a key.
    pub add_key_cost: AccessKeyCreationConfigView,

    /// Base cost of deleting a key.
    pub delete_key_cost: FeeView,

    /// Base cost of deleting an account.
    pub delete_account_cost: FeeView,

    /// Base cost for processing a delegate action.
    ///
    /// This is on top of the costs for the actions inside the delegate action.
    pub delegate_cost: FeeView,
}

/// Describes the cost of creating an access key.
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct AccessKeyCreationConfigView {
    /// Base cost of creating a full access access-key.
    pub full_access_cost: FeeView,
    /// Base cost of creating an access-key restricted to specific functions.
    pub function_call_cost: FeeView,
    /// Cost per byte of method_names of creating a restricted access-key.
    pub function_call_cost_per_byte: FeeView,
}

/// Describes cost of storage per block
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct StorageUsageConfigView {
    /// Number of bytes for an account record, including rounding up for account id.
    pub num_bytes_account: u64,
    /// Additional number of bytes for a k/v record
    pub num_extra_bytes_record: u64,
}

impl From<crate::RuntimeConfig> for RuntimeConfigView {
    fn from(config: crate::RuntimeConfig) -> Self {
        Self {
            storage_amount_per_byte: config.storage_amount_per_byte(),
            transaction_costs: RuntimeFeesConfigView {
                action_receipt_creation_config: config
                    .fees
                    .fee(ActionCosts::new_action_receipt)
                    .into(),
                data_receipt_creation_config: DataReceiptCreationConfigView {
                    base_cost: config.fees.fee(ActionCosts::new_data_receipt_base).into(),
                    cost_per_byte: config.fees.fee(ActionCosts::new_data_receipt_byte).into(),
                },
                action_creation_config: ActionCreationConfigView {
                    create_account_cost: config.fees.fee(ActionCosts::create_account).into(),
                    deploy_contract_cost: config.fees.fee(ActionCosts::deploy_contract_base).into(),
                    deploy_contract_cost_per_byte: config
                        .fees
                        .fee(ActionCosts::deploy_contract_byte)
                        .into(),
                    function_call_cost: config.fees.fee(ActionCosts::function_call_base).into(),
                    function_call_cost_per_byte: config
                        .fees
                        .fee(ActionCosts::function_call_byte)
                        .into(),
                    transfer_cost: config.fees.fee(ActionCosts::transfer).into(),
                    stake_cost: config.fees.fee(ActionCosts::stake).into(),
                    add_key_cost: AccessKeyCreationConfigView {
                        full_access_cost: config.fees.fee(ActionCosts::add_full_access_key).into(),
                        function_call_cost: config
                            .fees
                            .fee(ActionCosts::add_function_call_key_base)
                            .into(),
                        function_call_cost_per_byte: config
                            .fees
                            .fee(ActionCosts::add_function_call_key_byte)
                            .into(),
                    },
                    delete_key_cost: config.fees.fee(ActionCosts::delete_key).into(),
                    delete_account_cost: config.fees.fee(ActionCosts::delete_account).into(),
                    delegate_cost: config.fees.fee(ActionCosts::delegate).into(),
                },
                storage_usage_config: StorageUsageConfigView {
                    num_bytes_account: config.fees.storage_usage_config.num_bytes_account,
                    num_extra_bytes_record: config.fees.storage_usage_config.num_extra_bytes_record,
                },
                burnt_gas_reward: config.fees.burnt_gas_reward,
                pessimistic_gas_price_inflation_ratio: config
                    .fees
                    .pessimistic_gas_price_inflation_ratio,
                ml_dsa_65_verification_cost: config.fees.signature_verification_costs
                    [SignatureKind::MlDsa65]
                    .gas,
            },
            wasm_config: VMConfigView::from(crate::vm::Config::clone(&config.wasm_config)),
            account_creation_config: AccountCreationConfigView {
                min_allowed_top_level_account_length: config
                    .account_creation_config
                    .min_allowed_top_level_account_length,
                registrar_account_id: config.account_creation_config.registrar_account_id,
            },
            congestion_control_config: CongestionControlConfigView::from(
                config.congestion_control_config,
            ),
            witness_config: WitnessConfigView::from(config.witness_config),
            min_gas_purchase_price: config.min_gas_purchase_price,
            account_creation_charge: config.account_creation_charge,
        }
    }
}

#[derive(Clone, Debug, Hash, serde::Serialize, serde::Deserialize, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct VMConfigView {
    /// Costs for runtime externals
    pub ext_costs: ExtCostsConfigView,

    /// Gas cost of a growing memory by single page.
    pub grow_mem_cost: u32,
    /// Gas cost of a regular operation.
    pub regular_op_cost: u32,
    /// Base gas cost of a linear operation
    pub linear_op_base_cost: u64,
    /// Unit gas cost of a linear operation
    pub linear_op_unit_cost: u64,

    /// See [VMConfig::vm_kind](crate::vm::Config::vm_kind).
    pub vm_kind: crate::vm::VMKind,
    /// See [VMConfig::discard_custom_sections](crate::vm::Config::discard_custom_sections).
    pub discard_custom_sections: bool,
    /// See [VMConfig::global_contract_host_fns](crate::vm::Config::global_contract_host_fns).
    pub global_contract_host_fns: bool,
    /// See [VMConfig::reftypes_bulk_memory](crate::vm::Config::reftypes_bulk_memory).
    pub reftypes_bulk_memory: bool,
    /// See [VMConfig::gas_key_host_fns](crate::vm::Config::gas_key_host_fns).
    pub gas_key_host_fns: bool,
    /// See [VMConfig::one_yocto_on_promise](crate::vm::Config::one_yocto_on_promise).
    pub one_yocto_on_promise: bool,
    /// See [VMConfig::p256_verify_host_fn](crate::vm::Config::p256_verify_host_fn).
    pub p256_verify_host_fn: bool,
    /// See [VMConfig::yield_with_id_host_fns](crate::vm::Config::yield_with_id_host_fns).
    pub yield_with_id_host_fns: bool,
    /// See [VMConfig::chain_id_host_fn](crate::vm::Config::chain_id_host_fn).
    pub chain_id_host_fn: bool,
    /// See [VMConfig::bls12381_not_in_group_fix](crate::vm::Config::bls12381_not_in_group_fix).
    pub bls12381_not_in_group_fix: bool,

    /// See [VMConfig::storage_get_mode](crate::vm::Config::storage_get_mode).
    pub storage_get_mode: crate::vm::StorageGetMode,
    /// See [VMConfig::fix_contract_loading_cost](crate::vm::Config::fix_contract_loading_cost).
    pub fix_contract_loading_cost: bool,
    /// Deprecated
    pub implicit_account_creation: bool,
    /// See [VMConfig::eth_implicit_accounts](crate::vm::Config::eth_implicit_accounts).
    pub eth_implicit_accounts: bool,
    /// See [VMConfig::eth_implicit_global_contract](crate::vm::Config::eth_implicit_global_contract).
    pub eth_implicit_global_contract: bool,

    /// Describes limits for VM and Runtime.
    ///
    /// TODO: Consider changing this to `VMLimitConfigView` to avoid dependency
    /// on runtime.
    pub limit_config: crate::vm::LimitConfig,
}

impl From<crate::vm::Config> for VMConfigView {
    fn from(config: crate::vm::Config) -> Self {
        Self {
            ext_costs: ExtCostsConfigView::from(config.ext_costs),
            grow_mem_cost: config.grow_mem_cost,
            regular_op_cost: config.regular_op_cost,
            linear_op_base_cost: config.linear_op_base_cost,
            linear_op_unit_cost: config.linear_op_unit_cost,
            discard_custom_sections: config.discard_custom_sections,
            limit_config: config.limit_config,
            storage_get_mode: config.storage_get_mode,
            fix_contract_loading_cost: config.fix_contract_loading_cost,
            implicit_account_creation: true,
            vm_kind: config.vm_kind,
            eth_implicit_accounts: config.eth_implicit_accounts,
            eth_implicit_global_contract: config.eth_implicit_global_contract,
            global_contract_host_fns: config.global_contract_host_fns,
            reftypes_bulk_memory: config.reftypes_bulk_memory,
            gas_key_host_fns: config.gas_key_host_fns,
            one_yocto_on_promise: config.one_yocto_on_promise,
            p256_verify_host_fn: config.p256_verify_host_fn,
            yield_with_id_host_fns: config.yield_with_id_host_fns,
            chain_id_host_fn: config.chain_id_host_fn,
            bls12381_not_in_group_fix: config.bls12381_not_in_group_fix,
        }
    }
}

impl From<VMConfigView> for crate::vm::Config {
    fn from(view: VMConfigView) -> Self {
        Self {
            ext_costs: crate::ExtCostsConfig::from(view.ext_costs),
            grow_mem_cost: view.grow_mem_cost,
            regular_op_cost: view.regular_op_cost,
            linear_op_base_cost: view.linear_op_base_cost,
            linear_op_unit_cost: view.linear_op_unit_cost,
            discard_custom_sections: view.discard_custom_sections,
            limit_config: view.limit_config,
            storage_get_mode: view.storage_get_mode,
            fix_contract_loading_cost: view.fix_contract_loading_cost,
            vm_kind: view.vm_kind,
            eth_implicit_accounts: view.eth_implicit_accounts,
            eth_implicit_global_contract: view.eth_implicit_global_contract,
            global_contract_host_fns: view.global_contract_host_fns,
            reftypes_bulk_memory: view.reftypes_bulk_memory,
            gas_key_host_fns: view.gas_key_host_fns,
            one_yocto_on_promise: view.one_yocto_on_promise,
            p256_verify_host_fn: view.p256_verify_host_fn,
            yield_with_id_host_fns: view.yield_with_id_host_fns,
            chain_id_host_fn: view.chain_id_host_fn,
            bls12381_not_in_group_fix: view.bls12381_not_in_group_fix,
        }
    }
}

/// Typed view of ExtCostsConfig to preserve JSON output field names in protocol
/// config RPC output.
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct ExtCostsConfigView {
    /// Base cost for calling a host function.
    pub base: Gas,

    /// Base cost of loading a pre-compiled contract
    pub contract_loading_base: Gas,
    /// Cost per byte of loading a pre-compiled contract
    pub contract_loading_bytes: Gas,

    /// Base cost for guest memory read
    pub read_memory_base: Gas,
    /// Cost for guest memory read
    pub read_memory_byte: Gas,

    /// Base cost for guest memory write
    pub write_memory_base: Gas,

    /// Cost for guest memory write per byte
    pub write_memory_byte: Gas,

    /// Base cost for reading from register
    pub read_register_base: Gas,
    /// Cost for reading byte from register
    pub read_register_byte: Gas,

    /// Base cost for writing into register
    pub write_register_base: Gas,
    /// Cost for writing byte into register
    pub write_register_byte: Gas,

    /// Base cost of decoding utf8. It's used for `log_utf8` and `panic_utf8`.
    pub utf8_decoding_base: Gas,
    /// Cost per byte of decoding utf8. It's used for `log_utf8` and `panic_utf8`.
    pub utf8_decoding_byte: Gas,

    /// Base cost of decoding utf16. It's used for `log_utf16`.
    pub utf16_decoding_base: Gas,
    /// Cost per byte of decoding utf16. It's used for `log_utf16`.
    pub utf16_decoding_byte: Gas,

    /// Cost of getting sha256 base
    pub sha256_base: Gas,
    /// Cost of getting sha256 per byte
    pub sha256_byte: Gas,

    /// Cost of getting sha256 base
    pub keccak256_base: Gas,
    /// Cost of getting sha256 per byte
    pub keccak256_byte: Gas,

    /// Cost of getting sha256 base
    pub keccak512_base: Gas,
    /// Cost of getting sha256 per byte
    pub keccak512_byte: Gas,

    /// Cost of getting ripemd160 base
    pub ripemd160_base: Gas,
    /// Cost of getting ripemd160 per message block
    pub ripemd160_block: Gas,

    /// Cost of getting ed25519 base
    pub ed25519_verify_base: Gas,
    /// Cost of getting ed25519 per byte
    pub ed25519_verify_byte: Gas,

    /// Cost of calling ecrecover
    pub ecrecover_base: Gas,

    /// Cost of P-256 ECDSA signature verification base
    pub p256_verify_base: Gas,
    /// Cost of P-256 ECDSA signature verification per byte
    pub p256_verify_byte: Gas,

    /// Cost for calling logging.
    pub log_base: Gas,
    /// Cost for logging per byte
    pub log_byte: Gas,

    // ###############
    // # Storage API #
    // ###############
    /// Storage trie write key base cost
    pub storage_write_base: Gas,
    /// Storage trie write key per byte cost
    pub storage_write_key_byte: Gas,
    /// Storage trie write value per byte cost
    pub storage_write_value_byte: Gas,
    /// Storage trie write cost per byte of evicted value.
    pub storage_write_evicted_byte: Gas,

    /// Storage trie read key base cost
    pub storage_read_base: Gas,
    /// Storage trie read key per byte cost
    pub storage_read_key_byte: Gas,
    /// Storage trie read value cost per byte cost
    pub storage_read_value_byte: Gas,

    /// Storage trie read key overhead base cost, when doing large reads
    pub storage_large_read_overhead_base: Gas,
    /// Storage trie read key overhead  per-byte cost, when doing large reads
    pub storage_large_read_overhead_byte: Gas,

    /// Remove key from trie base cost
    pub storage_remove_base: Gas,
    /// Remove key from trie per byte cost
    pub storage_remove_key_byte: Gas,
    /// Remove key from trie ret value byte cost
    pub storage_remove_ret_value_byte: Gas,

    /// Storage trie check for key existence cost base
    pub storage_has_key_base: Gas,
    /// Storage trie check for key existence per key byte
    pub storage_has_key_byte: Gas,

    /// Create trie prefix iterator cost base
    pub storage_iter_create_prefix_base: Gas,
    /// Create trie prefix iterator cost per byte.
    pub storage_iter_create_prefix_byte: Gas,

    /// Create trie range iterator cost base
    pub storage_iter_create_range_base: Gas,
    /// Create trie range iterator cost per byte of from key.
    pub storage_iter_create_from_byte: Gas,
    /// Create trie range iterator cost per byte of to key.
    pub storage_iter_create_to_byte: Gas,

    /// Trie iterator per key base cost
    pub storage_iter_next_base: Gas,
    /// Trie iterator next key byte cost
    pub storage_iter_next_key_byte: Gas,
    /// Trie iterator next key byte cost
    pub storage_iter_next_value_byte: Gas,

    /// Cost per reading trie node from DB
    pub touching_trie_node: Gas,
    /// Cost for reading trie node from memory
    pub read_cached_trie_node: Gas,

    // ###############
    // # Promise API #
    // ###############
    /// Cost for calling `promise_and`
    pub promise_and_base: Gas,
    /// Cost for calling `promise_and` for each promise
    pub promise_and_per_promise: Gas,
    /// Cost for calling `promise_return`
    pub promise_return: Gas,

    // ###############
    // # Validator API #
    // ###############
    /// Cost of calling `validator_stake`.
    pub validator_stake_base: Gas,
    /// Cost of calling `validator_total_stake`.
    pub validator_total_stake_base: Gas,

    // Removed parameters, only here for keeping the output backward-compatible.
    pub contract_compile_base: Gas,
    pub contract_compile_bytes: Gas,

    // #############
    // # Alt BN128 #
    // #############
    /// Base cost for multiexp
    pub alt_bn128_g1_multiexp_base: Gas,
    /// Per element cost for multiexp
    pub alt_bn128_g1_multiexp_element: Gas,
    /// Base cost for sum
    pub alt_bn128_g1_sum_base: Gas,
    /// Per element cost for sum
    pub alt_bn128_g1_sum_element: Gas,
    /// Base cost for pairing check
    pub alt_bn128_pairing_check_base: Gas,
    /// Per element cost for pairing check
    pub alt_bn128_pairing_check_element: Gas,
    /// Base cost for creating a yield promise.
    pub yield_create_base: Gas,
    /// Per byte cost of arguments and method name.
    pub yield_create_byte: Gas,
    /// Base cost for creating a yield promise with a user-provided yield ID
    /// (covers the additional trie writes for the yield_id<->data_id mapping).
    pub yield_create_with_id_base: Gas,
    /// Base cost for resuming a yield receipt.
    pub yield_resume_base: Gas,
    /// Per byte cost of resume payload.
    pub yield_resume_byte: Gas,
    pub bls12381_p1_sum_base: Gas,
    pub bls12381_p1_sum_element: Gas,
    pub bls12381_p2_sum_base: Gas,
    pub bls12381_p2_sum_element: Gas,
    pub bls12381_g1_multiexp_base: Gas,
    pub bls12381_g1_multiexp_element: Gas,
    pub bls12381_g2_multiexp_base: Gas,
    pub bls12381_g2_multiexp_element: Gas,
    pub bls12381_map_fp_to_g1_base: Gas,
    pub bls12381_map_fp_to_g1_element: Gas,
    pub bls12381_map_fp2_to_g2_base: Gas,
    pub bls12381_map_fp2_to_g2_element: Gas,
    pub bls12381_pairing_base: Gas,
    pub bls12381_pairing_element: Gas,
    pub bls12381_p1_decompress_base: Gas,
    pub bls12381_p1_decompress_element: Gas,
    pub bls12381_p2_decompress_base: Gas,
    pub bls12381_p2_decompress_element: Gas,
}

impl From<crate::ExtCostsConfig> for ExtCostsConfigView {
    fn from(config: crate::ExtCostsConfig) -> Self {
        Self {
            base: config.gas_cost(ExtCosts::base),
            contract_loading_base: config.gas_cost(ExtCosts::contract_loading_base),
            contract_loading_bytes: config.gas_cost(ExtCosts::contract_loading_bytes),
            read_memory_base: config.gas_cost(ExtCosts::read_memory_base),
            read_memory_byte: config.gas_cost(ExtCosts::read_memory_byte),
            write_memory_base: config.gas_cost(ExtCosts::write_memory_base),
            write_memory_byte: config.gas_cost(ExtCosts::write_memory_byte),
            read_register_base: config.gas_cost(ExtCosts::read_register_base),
            read_register_byte: config.gas_cost(ExtCosts::read_register_byte),
            write_register_base: config.gas_cost(ExtCosts::write_register_base),
            write_register_byte: config.gas_cost(ExtCosts::write_register_byte),
            utf8_decoding_base: config.gas_cost(ExtCosts::utf8_decoding_base),
            utf8_decoding_byte: config.gas_cost(ExtCosts::utf8_decoding_byte),
            utf16_decoding_base: config.gas_cost(ExtCosts::utf16_decoding_base),
            utf16_decoding_byte: config.gas_cost(ExtCosts::utf16_decoding_byte),
            sha256_base: config.gas_cost(ExtCosts::sha256_base),
            sha256_byte: config.gas_cost(ExtCosts::sha256_byte),
            keccak256_base: config.gas_cost(ExtCosts::keccak256_base),
            keccak256_byte: config.gas_cost(ExtCosts::keccak256_byte),
            keccak512_base: config.gas_cost(ExtCosts::keccak512_base),
            keccak512_byte: config.gas_cost(ExtCosts::keccak512_byte),
            ripemd160_base: config.gas_cost(ExtCosts::ripemd160_base),
            ripemd160_block: config.gas_cost(ExtCosts::ripemd160_block),
            ed25519_verify_base: config.gas_cost(ExtCosts::ed25519_verify_base),
            ed25519_verify_byte: config.gas_cost(ExtCosts::ed25519_verify_byte),
            ecrecover_base: config.gas_cost(ExtCosts::ecrecover_base),
            p256_verify_base: config.gas_cost(ExtCosts::p256_verify_base),
            p256_verify_byte: config.gas_cost(ExtCosts::p256_verify_byte),
            log_base: config.gas_cost(ExtCosts::log_base),
            log_byte: config.gas_cost(ExtCosts::log_byte),
            storage_write_base: config.gas_cost(ExtCosts::storage_write_base),
            storage_write_key_byte: config.gas_cost(ExtCosts::storage_write_key_byte),
            storage_write_value_byte: config.gas_cost(ExtCosts::storage_write_value_byte),
            storage_write_evicted_byte: config.gas_cost(ExtCosts::storage_write_evicted_byte),
            storage_read_base: config.gas_cost(ExtCosts::storage_read_base),
            storage_read_key_byte: config.gas_cost(ExtCosts::storage_read_key_byte),
            storage_read_value_byte: config.gas_cost(ExtCosts::storage_read_value_byte),
            storage_large_read_overhead_base: config
                .gas_cost(ExtCosts::storage_large_read_overhead_base),
            storage_large_read_overhead_byte: config
                .gas_cost(ExtCosts::storage_large_read_overhead_byte),
            storage_remove_base: config.gas_cost(ExtCosts::storage_remove_base),
            storage_remove_key_byte: config.gas_cost(ExtCosts::storage_remove_key_byte),
            storage_remove_ret_value_byte: config.gas_cost(ExtCosts::storage_remove_ret_value_byte),
            storage_has_key_base: config.gas_cost(ExtCosts::storage_has_key_base),
            storage_has_key_byte: config.gas_cost(ExtCosts::storage_has_key_byte),
            storage_iter_create_prefix_base: config
                .gas_cost(ExtCosts::storage_iter_create_prefix_base),
            storage_iter_create_prefix_byte: config
                .gas_cost(ExtCosts::storage_iter_create_prefix_byte),
            storage_iter_create_range_base: config
                .gas_cost(ExtCosts::storage_iter_create_range_base),
            storage_iter_create_from_byte: config.gas_cost(ExtCosts::storage_iter_create_from_byte),
            storage_iter_create_to_byte: config.gas_cost(ExtCosts::storage_iter_create_to_byte),
            storage_iter_next_base: config.gas_cost(ExtCosts::storage_iter_next_base),
            storage_iter_next_key_byte: config.gas_cost(ExtCosts::storage_iter_next_key_byte),
            storage_iter_next_value_byte: config.gas_cost(ExtCosts::storage_iter_next_value_byte),
            touching_trie_node: config.gas_cost(ExtCosts::touching_trie_node),
            read_cached_trie_node: config.gas_cost(ExtCosts::read_cached_trie_node),
            promise_and_base: config.gas_cost(ExtCosts::promise_and_base),
            promise_and_per_promise: config.gas_cost(ExtCosts::promise_and_per_promise),
            promise_return: config.gas_cost(ExtCosts::promise_return),
            validator_stake_base: config.gas_cost(ExtCosts::validator_stake_base),
            validator_total_stake_base: config.gas_cost(ExtCosts::validator_total_stake_base),
            alt_bn128_g1_multiexp_base: config.gas_cost(ExtCosts::alt_bn128_g1_multiexp_base),
            alt_bn128_g1_multiexp_element: config.gas_cost(ExtCosts::alt_bn128_g1_multiexp_element),
            alt_bn128_g1_sum_base: config.gas_cost(ExtCosts::alt_bn128_g1_sum_base),
            alt_bn128_g1_sum_element: config.gas_cost(ExtCosts::alt_bn128_g1_sum_element),
            alt_bn128_pairing_check_base: config.gas_cost(ExtCosts::alt_bn128_pairing_check_base),
            alt_bn128_pairing_check_element: config
                .gas_cost(ExtCosts::alt_bn128_pairing_check_element),
            yield_create_base: config.gas_cost(ExtCosts::yield_create_base),
            yield_create_byte: config.gas_cost(ExtCosts::yield_create_byte),
            yield_create_with_id_base: config.gas_cost(ExtCosts::yield_create_with_id_base),
            yield_resume_base: config.gas_cost(ExtCosts::yield_resume_base),
            yield_resume_byte: config.gas_cost(ExtCosts::yield_resume_byte),
            bls12381_p1_sum_base: config.gas_cost(ExtCosts::bls12381_p1_sum_base),
            bls12381_p1_sum_element: config.gas_cost(ExtCosts::bls12381_p1_sum_element),
            bls12381_p2_sum_base: config.gas_cost(ExtCosts::bls12381_p2_sum_base),
            bls12381_p2_sum_element: config.gas_cost(ExtCosts::bls12381_p2_sum_element),
            bls12381_g1_multiexp_base: config.gas_cost(ExtCosts::bls12381_g1_multiexp_base),
            bls12381_g1_multiexp_element: config.gas_cost(ExtCosts::bls12381_g1_multiexp_element),
            bls12381_g2_multiexp_base: config.gas_cost(ExtCosts::bls12381_g2_multiexp_base),
            bls12381_g2_multiexp_element: config.gas_cost(ExtCosts::bls12381_g2_multiexp_element),
            bls12381_map_fp_to_g1_base: config.gas_cost(ExtCosts::bls12381_map_fp_to_g1_base),
            bls12381_map_fp_to_g1_element: config.gas_cost(ExtCosts::bls12381_map_fp_to_g1_element),
            bls12381_map_fp2_to_g2_base: config.gas_cost(ExtCosts::bls12381_map_fp2_to_g2_base),
            bls12381_map_fp2_to_g2_element: config
                .gas_cost(ExtCosts::bls12381_map_fp2_to_g2_element),
            bls12381_pairing_base: config.gas_cost(ExtCosts::bls12381_pairing_base),
            bls12381_pairing_element: config.gas_cost(ExtCosts::bls12381_pairing_element),
            bls12381_p1_decompress_base: config.gas_cost(ExtCosts::bls12381_p1_decompress_base),
            bls12381_p1_decompress_element: config
                .gas_cost(ExtCosts::bls12381_p1_decompress_element),
            bls12381_p2_decompress_base: config.gas_cost(ExtCosts::bls12381_p2_decompress_base),
            bls12381_p2_decompress_element: config
                .gas_cost(ExtCosts::bls12381_p2_decompress_element),
            // removed parameters
            contract_compile_base: Gas::ZERO,
            contract_compile_bytes: Gas::ZERO,
        }
    }
}

impl From<ExtCostsConfigView> for crate::ExtCostsConfig {
    fn from(view: ExtCostsConfigView) -> Self {
        let costs = enum_map::enum_map! {
                ExtCosts::base => view.base,
                ExtCosts::contract_loading_base => view.contract_loading_base,
                ExtCosts::contract_loading_bytes => view.contract_loading_bytes,
                ExtCosts::read_memory_base => view.read_memory_base,
                ExtCosts::read_memory_byte => view.read_memory_byte,
                ExtCosts::write_memory_base => view.write_memory_base,
                ExtCosts::write_memory_byte => view.write_memory_byte,
                ExtCosts::read_register_base => view.read_register_base,
                ExtCosts::read_register_byte => view.read_register_byte,
                ExtCosts::write_register_base => view.write_register_base,
                ExtCosts::write_register_byte => view.write_register_byte,
                ExtCosts::utf8_decoding_base => view.utf8_decoding_base,
                ExtCosts::utf8_decoding_byte => view.utf8_decoding_byte,
                ExtCosts::utf16_decoding_base => view.utf16_decoding_base,
                ExtCosts::utf16_decoding_byte => view.utf16_decoding_byte,
                ExtCosts::sha256_base => view.sha256_base,
                ExtCosts::sha256_byte => view.sha256_byte,
                ExtCosts::keccak256_base => view.keccak256_base,
                ExtCosts::keccak256_byte => view.keccak256_byte,
                ExtCosts::keccak512_base => view.keccak512_base,
                ExtCosts::keccak512_byte => view.keccak512_byte,
                ExtCosts::ripemd160_base => view.ripemd160_base,
                ExtCosts::ripemd160_block => view.ripemd160_block,
                ExtCosts::ed25519_verify_base => view.ed25519_verify_base,
                ExtCosts::ed25519_verify_byte => view.ed25519_verify_byte,
                ExtCosts::ecrecover_base => view.ecrecover_base,
                ExtCosts::p256_verify_base => view.p256_verify_base,
                ExtCosts::p256_verify_byte => view.p256_verify_byte,
                ExtCosts::log_base => view.log_base,
                ExtCosts::log_byte => view.log_byte,
                ExtCosts::storage_write_base => view.storage_write_base,
                ExtCosts::storage_write_key_byte => view.storage_write_key_byte,
                ExtCosts::storage_write_value_byte => view.storage_write_value_byte,
                ExtCosts::storage_write_evicted_byte => view.storage_write_evicted_byte,
                ExtCosts::storage_read_base => view.storage_read_base,
                ExtCosts::storage_read_key_byte => view.storage_read_key_byte,
                ExtCosts::storage_read_value_byte => view.storage_read_value_byte,
                ExtCosts::storage_large_read_overhead_base => view.storage_large_read_overhead_base,
                ExtCosts::storage_large_read_overhead_byte => view.storage_large_read_overhead_byte,
                ExtCosts::storage_remove_base => view.storage_remove_base,
                ExtCosts::storage_remove_key_byte => view.storage_remove_key_byte,
                ExtCosts::storage_remove_ret_value_byte => view.storage_remove_ret_value_byte,
                ExtCosts::storage_has_key_base => view.storage_has_key_base,
                ExtCosts::storage_has_key_byte => view.storage_has_key_byte,
                ExtCosts::storage_iter_create_prefix_base => view.storage_iter_create_prefix_base,
                ExtCosts::storage_iter_create_prefix_byte => view.storage_iter_create_prefix_byte,
                ExtCosts::storage_iter_create_range_base => view.storage_iter_create_range_base,
                ExtCosts::storage_iter_create_from_byte => view.storage_iter_create_from_byte,
                ExtCosts::storage_iter_create_to_byte => view.storage_iter_create_to_byte,
                ExtCosts::storage_iter_next_base => view.storage_iter_next_base,
                ExtCosts::storage_iter_next_key_byte => view.storage_iter_next_key_byte,
                ExtCosts::storage_iter_next_value_byte => view.storage_iter_next_value_byte,
                ExtCosts::touching_trie_node => view.touching_trie_node,
                ExtCosts::read_cached_trie_node => view.read_cached_trie_node,
                ExtCosts::promise_and_base => view.promise_and_base,
                ExtCosts::promise_and_per_promise => view.promise_and_per_promise,
                ExtCosts::promise_return => view.promise_return,
                ExtCosts::validator_stake_base => view.validator_stake_base,
                ExtCosts::validator_total_stake_base => view.validator_total_stake_base,
                ExtCosts::alt_bn128_g1_multiexp_base => view.alt_bn128_g1_multiexp_base,
                ExtCosts::alt_bn128_g1_multiexp_element => view.alt_bn128_g1_multiexp_element,
                ExtCosts::alt_bn128_g1_sum_base => view.alt_bn128_g1_sum_base,
                ExtCosts::alt_bn128_g1_sum_element => view.alt_bn128_g1_sum_element,
                ExtCosts::alt_bn128_pairing_check_base => view.alt_bn128_pairing_check_base,
                ExtCosts::alt_bn128_pairing_check_element => view.alt_bn128_pairing_check_element,
                ExtCosts::yield_create_base => view.yield_create_base,
                ExtCosts::yield_create_byte => view.yield_create_byte,
                ExtCosts::yield_create_with_id_base => view.yield_create_with_id_base,
                ExtCosts::yield_resume_base => view.yield_resume_base,
                ExtCosts::yield_resume_byte => view.yield_resume_byte,
                ExtCosts::bls12381_p1_sum_base => view.bls12381_p1_sum_base,
                ExtCosts::bls12381_p1_sum_element => view.bls12381_p1_sum_element,
                ExtCosts::bls12381_p2_sum_base => view.bls12381_p2_sum_base,
                ExtCosts::bls12381_p2_sum_element => view.bls12381_p2_sum_element,
                ExtCosts::bls12381_g1_multiexp_base => view.bls12381_g1_multiexp_base,
                ExtCosts::bls12381_g1_multiexp_element => view.bls12381_g1_multiexp_element,
                ExtCosts::bls12381_g2_multiexp_base => view.bls12381_g2_multiexp_base,
                ExtCosts::bls12381_g2_multiexp_element => view.bls12381_g2_multiexp_element,
                ExtCosts::bls12381_map_fp_to_g1_base => view.bls12381_map_fp_to_g1_base,
                ExtCosts::bls12381_map_fp_to_g1_element => view.bls12381_map_fp_to_g1_element,
                ExtCosts::bls12381_map_fp2_to_g2_base => view.bls12381_map_fp2_to_g2_base,
                ExtCosts::bls12381_map_fp2_to_g2_element => view.bls12381_map_fp2_to_g2_element,
                ExtCosts::bls12381_pairing_base => view.bls12381_pairing_base,
                ExtCosts::bls12381_pairing_element => view.bls12381_pairing_element,
                ExtCosts::bls12381_p1_decompress_base => view.bls12381_p1_decompress_base,
                ExtCosts::bls12381_p1_decompress_element => view.bls12381_p1_decompress_element,
                ExtCosts::bls12381_p2_decompress_base => view.bls12381_p2_decompress_base,
                ExtCosts::bls12381_p2_decompress_element => view.bls12381_p2_decompress_element,
        }
        .map(|_, value| ParameterCost { gas: value, compute: value.as_gas() });
        Self { costs }
    }
}

/// Configuration specific to ChunkStateWitness.
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct WitnessConfigView {
    /// Size limit for storage proof generated while executing receipts in a chunk.
    /// After this limit is reached we defer execution of any new receipts.
    pub main_storage_proof_size_soft_limit: u64,
    /// Maximum size of transactions contained inside ChunkStateWitness.
    ///
    /// A witness contains transactions from both the previous chunk and the current one.
    /// This parameter limits the sum of sizes of transactions from both of those chunks.
    pub combined_transactions_size_limit: usize,
    /// Soft size limit of storage proof used to validate new transactions in ChunkStateWitness.
    pub new_transactions_validation_state_size_soft_limit: u64,
}

impl From<WitnessConfig> for WitnessConfigView {
    fn from(config: WitnessConfig) -> Self {
        Self {
            main_storage_proof_size_soft_limit: config.main_storage_proof_size_soft_limit,
            combined_transactions_size_limit: config.combined_transactions_size_limit,
            new_transactions_validation_state_size_soft_limit: config
                .new_transactions_validation_state_size_soft_limit,
        }
    }
}

/// The configuration for congestion control. More info about congestion [here](https://near.github.io/nearcore/architecture/how/receipt-congestion.html?highlight=congestion#receipt-congestion)
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct CongestionControlConfigView {
    /// How much gas in delayed receipts of a shard is 100% incoming congestion.
    ///
    /// See [`CongestionControlConfig`] for more details.
    pub max_congestion_incoming_gas: Gas,

    /// How much gas in outgoing buffered receipts of a shard is 100% congested.
    ///
    /// Outgoing congestion contributes to overall congestion, which reduces how
    /// much other shards are allowed to forward to this shard.
    pub max_congestion_outgoing_gas: Gas,

    /// How much memory space of all delayed and buffered receipts in a shard is
    /// considered 100% congested.
    ///
    /// See [`CongestionControlConfig`] for more details.
    pub max_congestion_memory_consumption: u64,

    /// How many missed chunks in a row in a shard is considered 100% congested.
    pub max_congestion_missed_chunks: u64,

    /// The maximum amount of gas attached to receipts a shard can forward to
    /// another shard per chunk.
    ///
    /// See [`CongestionControlConfig`] for more details.
    pub max_outgoing_gas: Gas,

    /// The minimum gas each shard can send to a shard that is not fully congested.
    ///
    /// See [`CongestionControlConfig`] for more details.
    pub min_outgoing_gas: Gas,

    /// How much gas the chosen allowed shard can send to a 100% congested shard.
    ///
    /// See [`CongestionControlConfig`] for more details.
    pub allowed_shard_outgoing_gas: Gas,

    /// The maximum amount of gas in a chunk spent on converting new transactions to
    /// receipts.
    ///
    /// See [`CongestionControlConfig`] for more details.
    pub max_tx_gas: Gas,

    /// The minimum amount of gas in a chunk spent on converting new transactions
    /// to receipts, as long as the receiving shard is not congested.
    ///
    /// See [`CongestionControlConfig`] for more details.
    pub min_tx_gas: Gas,

    /// How much congestion a shard can tolerate before it stops all shards from
    /// accepting new transactions with the receiver set to the congested shard.
    pub reject_tx_congestion_threshold: f64,

    /// The standard size limit for outgoing receipts aimed at a single shard.
    /// This limit is pretty small to keep the size of source_receipt_proofs under control.
    /// It limits the total sum of outgoing receipts, not individual receipts.
    pub outgoing_receipts_usual_size_limit: u64,

    /// Large size limit for outgoing receipts to a shard, used when it's safe
    /// to send a lot of receipts without making the state witness too large.
    /// It limits the total sum of outgoing receipts, not individual receipts.
    pub outgoing_receipts_big_size_limit: u64,
}

impl From<CongestionControlConfig> for CongestionControlConfigView {
    fn from(other: CongestionControlConfig) -> Self {
        Self {
            max_congestion_incoming_gas: other.max_congestion_incoming_gas,
            max_congestion_outgoing_gas: other.max_congestion_outgoing_gas,
            max_congestion_memory_consumption: other.max_congestion_memory_consumption,
            max_congestion_missed_chunks: other.max_congestion_missed_chunks,
            max_outgoing_gas: other.max_outgoing_gas,
            min_outgoing_gas: other.min_outgoing_gas,
            allowed_shard_outgoing_gas: other.allowed_shard_outgoing_gas,
            max_tx_gas: other.max_tx_gas,
            min_tx_gas: other.min_tx_gas,
            reject_tx_congestion_threshold: other.reject_tx_congestion_threshold,
            outgoing_receipts_usual_size_limit: other.outgoing_receipts_usual_size_limit,
            outgoing_receipts_big_size_limit: other.outgoing_receipts_big_size_limit,
        }
    }
}

impl From<CongestionControlConfigView> for CongestionControlConfig {
    fn from(other: CongestionControlConfigView) -> Self {
        Self {
            max_congestion_incoming_gas: other.max_congestion_incoming_gas,
            max_congestion_outgoing_gas: other.max_congestion_outgoing_gas,
            max_congestion_memory_consumption: other.max_congestion_memory_consumption,
            max_congestion_missed_chunks: other.max_congestion_missed_chunks,
            max_outgoing_gas: other.max_outgoing_gas,
            min_outgoing_gas: other.min_outgoing_gas,
            allowed_shard_outgoing_gas: other.allowed_shard_outgoing_gas,
            max_tx_gas: other.max_tx_gas,
            min_tx_gas: other.min_tx_gas,
            reject_tx_congestion_threshold: other.reject_tx_congestion_threshold,
            outgoing_receipts_usual_size_limit: other.outgoing_receipts_usual_size_limit,
            outgoing_receipts_big_size_limit: other.outgoing_receipts_big_size_limit,
        }
    }
}

/// Costs associated with an object that can only be sent over the network (and executed
/// by the receiver).
/// NOTE: `send_sir` or `send_not_sir` fees are usually burned when the item is being created.
/// And `execution` fee is burned when the item is being executed.
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
#[serde(rename = "Fee")]
pub struct FeeView {
    /// Fee for sending an object from the sender to itself, guaranteeing that it does not leave
    /// the shard.
    pub send_sir: Gas,
    /// Fee for sending an object potentially across the shards.
    pub send_not_sir: Gas,
    /// Fee for executing the object.
    pub execution: Gas,
}

impl From<&Fee> for FeeView {
    fn from(other: &Fee) -> Self {
        Self {
            send_sir: other.send_sir.gas(),
            send_not_sir: other.send_not_sir.gas(),
            execution: other.execution.gas(),
        }
    }
}

#[cfg(feature = "schemars")]
pub type Rational32SchemarsProvider = [i32; 2];

#[cfg(test)]
#[cfg(not(feature = "nightly"))]
mod tests {
    /// The JSON representation used in RPC responses must not remove or rename
    /// fields, only adding fields is allowed or we risk breaking clients.
    #[test]
    fn test_runtime_config_view() {
        use crate::RuntimeConfig;
        use crate::RuntimeConfigStore;
        use crate::view::RuntimeConfigView;
        use near_primitives_core::version::PROTOCOL_VERSION;

        let config_store = RuntimeConfigStore::new(None);
        let config = config_store.get_config(PROTOCOL_VERSION);
        let view = RuntimeConfigView::from(RuntimeConfig::clone(config));
        insta::assert_json_snapshot!(&view, { ".wasm_config.vm_kind" => "<REDACTED>"});
    }
}
