diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cc57f6d80..70cb1f6aba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE ### Changed +- Implement faster cost tracker for default cost functions in Clarity - Miner will stop waiting for signatures on a block if the Stacks tip advances (causing the block it had proposed to be invalid). - Logging improvements: - P2P logs now includes a reason for dropping a peer or neighbor diff --git a/clarity/src/vm/contexts.rs b/clarity/src/vm/contexts.rs index 7c47e93eb2..87c9d56de1 100644 --- a/clarity/src/vm/contexts.rs +++ b/clarity/src/vm/contexts.rs @@ -715,6 +715,10 @@ impl<'a, 'hooks> OwnedEnvironment<'a, 'hooks> { }) } + pub fn is_mainnet(&self) -> bool { + self.context.mainnet + } + #[cfg(any(test, feature = "testing"))] pub fn stx_faucet(&mut self, recipient: &PrincipalData, amount: u128) { self.execute_in_env::<_, _, crate::vm::errors::Error>( diff --git a/clarity/src/vm/costs/cost_functions.rs b/clarity/src/vm/costs/cost_functions.rs index 9c9e65864f..dc2a81585a 100644 --- a/clarity/src/vm/costs/cost_functions.rs +++ b/clarity/src/vm/costs/cost_functions.rs @@ -14,6 +14,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use super::ExecutionCost; +use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; + define_named_enum!(ClarityCostFunction { AnalysisTypeAnnotate("cost_analysis_type_annotate"), AnalysisTypeCheck("cost_analysis_type_check"), @@ -156,3 +159,326 @@ define_named_enum!(ClarityCostFunction { BitwiseRShift("cost_bitwise_right_shift"), Unimplemented("cost_unimplemented"), }); + +// Helper functions used by `CostValues` implementations + +pub fn linear(n: u64, a: u64, b: u64) -> u64 { + a.saturating_mul(n).saturating_add(b) +} +pub fn logn(n: u64, a: u64, b: u64) -> InterpreterResult { + if n < 1 { + return Err(crate::vm::errors::Error::Runtime( + RuntimeErrorType::Arithmetic("log2 must be passed a positive integer".to_string()), + Some(vec![]), + )); + } + let nlog2 = u64::from(64 - 1 - n.leading_zeros()); + Ok(a.saturating_mul(nlog2).saturating_add(b)) +} +pub fn nlogn(n: u64, a: u64, b: u64) -> InterpreterResult { + if n < 1 { + return Err(crate::vm::errors::Error::Runtime( + RuntimeErrorType::Arithmetic("log2 must be passed a positive integer".to_string()), + Some(vec![]), + )); + } + let nlog2 = u64::from(64 - 1 - n.leading_zeros()); + Ok(a.saturating_mul(nlog2.saturating_mul(n)).saturating_add(b)) +} + +pub trait CostValues { + fn cost_analysis_type_annotate(n: u64) -> InterpreterResult; + fn cost_analysis_type_check(n: u64) -> InterpreterResult; + fn cost_analysis_type_lookup(n: u64) -> InterpreterResult; + fn cost_analysis_visit(n: u64) -> InterpreterResult; + fn cost_analysis_iterable_func(n: u64) -> InterpreterResult; + fn cost_analysis_option_cons(n: u64) -> InterpreterResult; + fn cost_analysis_option_check(n: u64) -> InterpreterResult; + fn cost_analysis_bind_name(n: u64) -> InterpreterResult; + fn cost_analysis_list_items_check(n: u64) -> InterpreterResult; + fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult; + fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult; + fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult; + fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult; + fn cost_analysis_check_let(n: u64) -> InterpreterResult; + fn cost_analysis_lookup_function(n: u64) -> InterpreterResult; + fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult; + fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult; + fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult; + fn cost_ast_parse(n: u64) -> InterpreterResult; + fn cost_ast_cycle_detection(n: u64) -> InterpreterResult; + fn cost_analysis_storage(n: u64) -> InterpreterResult; + fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult; + fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult; + fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult; + fn cost_lookup_variable_depth(n: u64) -> InterpreterResult; + fn cost_lookup_variable_size(n: u64) -> InterpreterResult; + fn cost_lookup_function(n: u64) -> InterpreterResult; + fn cost_bind_name(n: u64) -> InterpreterResult; + fn cost_inner_type_check_cost(n: u64) -> InterpreterResult; + fn cost_user_function_application(n: u64) -> InterpreterResult; + fn cost_let(n: u64) -> InterpreterResult; + fn cost_if(n: u64) -> InterpreterResult; + fn cost_asserts(n: u64) -> InterpreterResult; + fn cost_map(n: u64) -> InterpreterResult; + fn cost_filter(n: u64) -> InterpreterResult; + fn cost_len(n: u64) -> InterpreterResult; + fn cost_element_at(n: u64) -> InterpreterResult; + fn cost_index_of(n: u64) -> InterpreterResult; + fn cost_fold(n: u64) -> InterpreterResult; + fn cost_list_cons(n: u64) -> InterpreterResult; + fn cost_type_parse_step(n: u64) -> InterpreterResult; + fn cost_tuple_get(n: u64) -> InterpreterResult; + fn cost_tuple_merge(n: u64) -> InterpreterResult; + fn cost_tuple_cons(n: u64) -> InterpreterResult; + fn cost_add(n: u64) -> InterpreterResult; + fn cost_sub(n: u64) -> InterpreterResult; + fn cost_mul(n: u64) -> InterpreterResult; + fn cost_div(n: u64) -> InterpreterResult; + fn cost_geq(n: u64) -> InterpreterResult; + fn cost_leq(n: u64) -> InterpreterResult; + fn cost_le(n: u64) -> InterpreterResult; + fn cost_ge(n: u64) -> InterpreterResult; + fn cost_int_cast(n: u64) -> InterpreterResult; + fn cost_mod(n: u64) -> InterpreterResult; + fn cost_pow(n: u64) -> InterpreterResult; + fn cost_sqrti(n: u64) -> InterpreterResult; + fn cost_log2(n: u64) -> InterpreterResult; + fn cost_xor(n: u64) -> InterpreterResult; + fn cost_not(n: u64) -> InterpreterResult; + fn cost_eq(n: u64) -> InterpreterResult; + fn cost_begin(n: u64) -> InterpreterResult; + fn cost_hash160(n: u64) -> InterpreterResult; + fn cost_sha256(n: u64) -> InterpreterResult; + fn cost_sha512(n: u64) -> InterpreterResult; + fn cost_sha512t256(n: u64) -> InterpreterResult; + fn cost_keccak256(n: u64) -> InterpreterResult; + fn cost_secp256k1recover(n: u64) -> InterpreterResult; + fn cost_secp256k1verify(n: u64) -> InterpreterResult; + fn cost_print(n: u64) -> InterpreterResult; + fn cost_some_cons(n: u64) -> InterpreterResult; + fn cost_ok_cons(n: u64) -> InterpreterResult; + fn cost_err_cons(n: u64) -> InterpreterResult; + fn cost_default_to(n: u64) -> InterpreterResult; + fn cost_unwrap_ret(n: u64) -> InterpreterResult; + fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult; + fn cost_is_okay(n: u64) -> InterpreterResult; + fn cost_is_none(n: u64) -> InterpreterResult; + fn cost_is_err(n: u64) -> InterpreterResult; + fn cost_is_some(n: u64) -> InterpreterResult; + fn cost_unwrap(n: u64) -> InterpreterResult; + fn cost_unwrap_err(n: u64) -> InterpreterResult; + fn cost_try_ret(n: u64) -> InterpreterResult; + fn cost_match(n: u64) -> InterpreterResult; + fn cost_or(n: u64) -> InterpreterResult; + fn cost_and(n: u64) -> InterpreterResult; + fn cost_append(n: u64) -> InterpreterResult; + fn cost_concat(n: u64) -> InterpreterResult; + fn cost_as_max_len(n: u64) -> InterpreterResult; + fn cost_contract_call(n: u64) -> InterpreterResult; + fn cost_contract_of(n: u64) -> InterpreterResult; + fn cost_principal_of(n: u64) -> InterpreterResult; + fn cost_at_block(n: u64) -> InterpreterResult; + fn cost_load_contract(n: u64) -> InterpreterResult; + fn cost_create_map(n: u64) -> InterpreterResult; + fn cost_create_var(n: u64) -> InterpreterResult; + fn cost_create_nft(n: u64) -> InterpreterResult; + fn cost_create_ft(n: u64) -> InterpreterResult; + fn cost_fetch_entry(n: u64) -> InterpreterResult; + fn cost_set_entry(n: u64) -> InterpreterResult; + fn cost_fetch_var(n: u64) -> InterpreterResult; + fn cost_set_var(n: u64) -> InterpreterResult; + fn cost_contract_storage(n: u64) -> InterpreterResult; + fn cost_block_info(n: u64) -> InterpreterResult; + fn cost_stx_balance(n: u64) -> InterpreterResult; + fn cost_stx_transfer(n: u64) -> InterpreterResult; + fn cost_ft_mint(n: u64) -> InterpreterResult; + fn cost_ft_transfer(n: u64) -> InterpreterResult; + fn cost_ft_balance(n: u64) -> InterpreterResult; + fn cost_ft_get_supply(n: u64) -> InterpreterResult; + fn cost_ft_burn(n: u64) -> InterpreterResult; + fn cost_nft_mint(n: u64) -> InterpreterResult; + fn cost_nft_transfer(n: u64) -> InterpreterResult; + fn cost_nft_owner(n: u64) -> InterpreterResult; + fn cost_nft_burn(n: u64) -> InterpreterResult; + fn poison_microblock(n: u64) -> InterpreterResult; + fn cost_buff_to_int_le(n: u64) -> InterpreterResult; + fn cost_buff_to_uint_le(n: u64) -> InterpreterResult; + fn cost_buff_to_int_be(n: u64) -> InterpreterResult; + fn cost_buff_to_uint_be(n: u64) -> InterpreterResult; + fn cost_is_standard(n: u64) -> InterpreterResult; + fn cost_principal_destruct(n: u64) -> InterpreterResult; + fn cost_principal_construct(n: u64) -> InterpreterResult; + fn cost_string_to_int(n: u64) -> InterpreterResult; + fn cost_string_to_uint(n: u64) -> InterpreterResult; + fn cost_int_to_ascii(n: u64) -> InterpreterResult; + fn cost_int_to_utf8(n: u64) -> InterpreterResult; + fn cost_burn_block_info(n: u64) -> InterpreterResult; + fn cost_stx_account(n: u64) -> InterpreterResult; + fn cost_slice(n: u64) -> InterpreterResult; + fn cost_to_consensus_buff(n: u64) -> InterpreterResult; + fn cost_from_consensus_buff(n: u64) -> InterpreterResult; + fn cost_stx_transfer_memo(n: u64) -> InterpreterResult; + fn cost_replace_at(n: u64) -> InterpreterResult; + fn cost_as_contract(n: u64) -> InterpreterResult; + fn cost_bitwise_and(n: u64) -> InterpreterResult; + fn cost_bitwise_or(n: u64) -> InterpreterResult; + fn cost_bitwise_not(n: u64) -> InterpreterResult; + fn cost_bitwise_left_shift(n: u64) -> InterpreterResult; + fn cost_bitwise_right_shift(n: u64) -> InterpreterResult; +} + +impl ClarityCostFunction { + pub fn eval(&self, n: u64) -> InterpreterResult { + match self { + ClarityCostFunction::AnalysisTypeAnnotate => C::cost_analysis_type_annotate(n), + ClarityCostFunction::AnalysisTypeCheck => C::cost_analysis_type_check(n), + ClarityCostFunction::AnalysisTypeLookup => C::cost_analysis_type_lookup(n), + ClarityCostFunction::AnalysisVisit => C::cost_analysis_visit(n), + ClarityCostFunction::AnalysisIterableFunc => C::cost_analysis_iterable_func(n), + ClarityCostFunction::AnalysisOptionCons => C::cost_analysis_option_cons(n), + ClarityCostFunction::AnalysisOptionCheck => C::cost_analysis_option_check(n), + ClarityCostFunction::AnalysisBindName => C::cost_analysis_bind_name(n), + ClarityCostFunction::AnalysisListItemsCheck => C::cost_analysis_list_items_check(n), + ClarityCostFunction::AnalysisCheckTupleGet => C::cost_analysis_check_tuple_get(n), + ClarityCostFunction::AnalysisCheckTupleMerge => C::cost_analysis_check_tuple_merge(n), + ClarityCostFunction::AnalysisCheckTupleCons => C::cost_analysis_check_tuple_cons(n), + ClarityCostFunction::AnalysisTupleItemsCheck => C::cost_analysis_tuple_items_check(n), + ClarityCostFunction::AnalysisCheckLet => C::cost_analysis_check_let(n), + ClarityCostFunction::AnalysisLookupFunction => C::cost_analysis_lookup_function(n), + ClarityCostFunction::AnalysisLookupFunctionTypes => { + C::cost_analysis_lookup_function_types(n) + } + ClarityCostFunction::AnalysisLookupVariableConst => { + C::cost_analysis_lookup_variable_const(n) + } + ClarityCostFunction::AnalysisLookupVariableDepth => { + C::cost_analysis_lookup_variable_depth(n) + } + ClarityCostFunction::AstParse => C::cost_ast_parse(n), + ClarityCostFunction::AstCycleDetection => C::cost_ast_cycle_detection(n), + ClarityCostFunction::AnalysisStorage => C::cost_analysis_storage(n), + ClarityCostFunction::AnalysisUseTraitEntry => C::cost_analysis_use_trait_entry(n), + ClarityCostFunction::AnalysisGetFunctionEntry => C::cost_analysis_get_function_entry(n), + ClarityCostFunction::AnalysisFetchContractEntry => { + C::cost_analysis_fetch_contract_entry(n) + } + ClarityCostFunction::LookupVariableDepth => C::cost_lookup_variable_depth(n), + ClarityCostFunction::LookupVariableSize => C::cost_lookup_variable_size(n), + ClarityCostFunction::LookupFunction => C::cost_lookup_function(n), + ClarityCostFunction::BindName => C::cost_bind_name(n), + ClarityCostFunction::InnerTypeCheckCost => C::cost_inner_type_check_cost(n), + ClarityCostFunction::UserFunctionApplication => C::cost_user_function_application(n), + ClarityCostFunction::Let => C::cost_let(n), + ClarityCostFunction::If => C::cost_if(n), + ClarityCostFunction::Asserts => C::cost_asserts(n), + ClarityCostFunction::Map => C::cost_map(n), + ClarityCostFunction::Filter => C::cost_filter(n), + ClarityCostFunction::Len => C::cost_len(n), + ClarityCostFunction::ElementAt => C::cost_element_at(n), + ClarityCostFunction::IndexOf => C::cost_index_of(n), + ClarityCostFunction::Fold => C::cost_fold(n), + ClarityCostFunction::ListCons => C::cost_list_cons(n), + ClarityCostFunction::TypeParseStep => C::cost_type_parse_step(n), + ClarityCostFunction::TupleGet => C::cost_tuple_get(n), + ClarityCostFunction::TupleMerge => C::cost_tuple_merge(n), + ClarityCostFunction::TupleCons => C::cost_tuple_cons(n), + ClarityCostFunction::Add => C::cost_add(n), + ClarityCostFunction::Sub => C::cost_sub(n), + ClarityCostFunction::Mul => C::cost_mul(n), + ClarityCostFunction::Div => C::cost_div(n), + ClarityCostFunction::Geq => C::cost_geq(n), + ClarityCostFunction::Leq => C::cost_leq(n), + ClarityCostFunction::Le => C::cost_le(n), + ClarityCostFunction::Ge => C::cost_ge(n), + ClarityCostFunction::IntCast => C::cost_int_cast(n), + ClarityCostFunction::Mod => C::cost_mod(n), + ClarityCostFunction::Pow => C::cost_pow(n), + ClarityCostFunction::Sqrti => C::cost_sqrti(n), + ClarityCostFunction::Log2 => C::cost_log2(n), + ClarityCostFunction::Xor => C::cost_xor(n), + ClarityCostFunction::Not => C::cost_not(n), + ClarityCostFunction::Eq => C::cost_eq(n), + ClarityCostFunction::Begin => C::cost_begin(n), + ClarityCostFunction::Hash160 => C::cost_hash160(n), + ClarityCostFunction::Sha256 => C::cost_sha256(n), + ClarityCostFunction::Sha512 => C::cost_sha512(n), + ClarityCostFunction::Sha512t256 => C::cost_sha512t256(n), + ClarityCostFunction::Keccak256 => C::cost_keccak256(n), + ClarityCostFunction::Secp256k1recover => C::cost_secp256k1recover(n), + ClarityCostFunction::Secp256k1verify => C::cost_secp256k1verify(n), + ClarityCostFunction::Print => C::cost_print(n), + ClarityCostFunction::SomeCons => C::cost_some_cons(n), + ClarityCostFunction::OkCons => C::cost_ok_cons(n), + ClarityCostFunction::ErrCons => C::cost_err_cons(n), + ClarityCostFunction::DefaultTo => C::cost_default_to(n), + ClarityCostFunction::UnwrapRet => C::cost_unwrap_ret(n), + ClarityCostFunction::UnwrapErrOrRet => C::cost_unwrap_err_or_ret(n), + ClarityCostFunction::IsOkay => C::cost_is_okay(n), + ClarityCostFunction::IsNone => C::cost_is_none(n), + ClarityCostFunction::IsErr => C::cost_is_err(n), + ClarityCostFunction::IsSome => C::cost_is_some(n), + ClarityCostFunction::Unwrap => C::cost_unwrap(n), + ClarityCostFunction::UnwrapErr => C::cost_unwrap_err(n), + ClarityCostFunction::TryRet => C::cost_try_ret(n), + ClarityCostFunction::Match => C::cost_match(n), + ClarityCostFunction::Or => C::cost_or(n), + ClarityCostFunction::And => C::cost_and(n), + ClarityCostFunction::Append => C::cost_append(n), + ClarityCostFunction::Concat => C::cost_concat(n), + ClarityCostFunction::AsMaxLen => C::cost_as_max_len(n), + ClarityCostFunction::ContractCall => C::cost_contract_call(n), + ClarityCostFunction::ContractOf => C::cost_contract_of(n), + ClarityCostFunction::PrincipalOf => C::cost_principal_of(n), + ClarityCostFunction::AtBlock => C::cost_at_block(n), + ClarityCostFunction::LoadContract => C::cost_load_contract(n), + ClarityCostFunction::CreateMap => C::cost_create_map(n), + ClarityCostFunction::CreateVar => C::cost_create_var(n), + ClarityCostFunction::CreateNft => C::cost_create_nft(n), + ClarityCostFunction::CreateFt => C::cost_create_ft(n), + ClarityCostFunction::FetchEntry => C::cost_fetch_entry(n), + ClarityCostFunction::SetEntry => C::cost_set_entry(n), + ClarityCostFunction::FetchVar => C::cost_fetch_var(n), + ClarityCostFunction::SetVar => C::cost_set_var(n), + ClarityCostFunction::ContractStorage => C::cost_contract_storage(n), + ClarityCostFunction::BlockInfo => C::cost_block_info(n), + ClarityCostFunction::StxBalance => C::cost_stx_balance(n), + ClarityCostFunction::StxTransfer => C::cost_stx_transfer(n), + ClarityCostFunction::FtMint => C::cost_ft_mint(n), + ClarityCostFunction::FtTransfer => C::cost_ft_transfer(n), + ClarityCostFunction::FtBalance => C::cost_ft_balance(n), + ClarityCostFunction::FtSupply => C::cost_ft_get_supply(n), + ClarityCostFunction::FtBurn => C::cost_ft_burn(n), + ClarityCostFunction::NftMint => C::cost_nft_mint(n), + ClarityCostFunction::NftTransfer => C::cost_nft_transfer(n), + ClarityCostFunction::NftOwner => C::cost_nft_owner(n), + ClarityCostFunction::NftBurn => C::cost_nft_burn(n), + ClarityCostFunction::PoisonMicroblock => C::poison_microblock(n), + ClarityCostFunction::BuffToIntLe => C::cost_buff_to_int_le(n), + ClarityCostFunction::BuffToUIntLe => C::cost_buff_to_uint_le(n), + ClarityCostFunction::BuffToIntBe => C::cost_buff_to_int_be(n), + ClarityCostFunction::BuffToUIntBe => C::cost_buff_to_uint_be(n), + ClarityCostFunction::IsStandard => C::cost_is_standard(n), + ClarityCostFunction::PrincipalDestruct => C::cost_principal_destruct(n), + ClarityCostFunction::PrincipalConstruct => C::cost_principal_construct(n), + ClarityCostFunction::StringToInt => C::cost_string_to_int(n), + ClarityCostFunction::StringToUInt => C::cost_string_to_uint(n), + ClarityCostFunction::IntToAscii => C::cost_int_to_ascii(n), + ClarityCostFunction::IntToUtf8 => C::cost_int_to_utf8(n), + ClarityCostFunction::GetBurnBlockInfo => C::cost_burn_block_info(n), + ClarityCostFunction::StxGetAccount => C::cost_stx_account(n), + ClarityCostFunction::Slice => C::cost_slice(n), + ClarityCostFunction::ToConsensusBuff => C::cost_to_consensus_buff(n), + ClarityCostFunction::FromConsensusBuff => C::cost_from_consensus_buff(n), + ClarityCostFunction::StxTransferMemo => C::cost_stx_transfer_memo(n), + ClarityCostFunction::ReplaceAt => C::cost_replace_at(n), + ClarityCostFunction::AsContract => C::cost_as_contract(n), + ClarityCostFunction::BitwiseAnd => C::cost_bitwise_and(n), + ClarityCostFunction::BitwiseOr => C::cost_bitwise_or(n), + ClarityCostFunction::BitwiseNot => C::cost_bitwise_not(n), + ClarityCostFunction::BitwiseLShift => C::cost_bitwise_left_shift(n), + ClarityCostFunction::BitwiseRShift => C::cost_bitwise_right_shift(n), + ClarityCostFunction::Unimplemented => Err(RuntimeErrorType::NotImplemented.into()), + } + } +} diff --git a/clarity/src/vm/costs/costs_1.rs b/clarity/src/vm/costs/costs_1.rs new file mode 100644 index 0000000000..71a319f75a --- /dev/null +++ b/clarity/src/vm/costs/costs_1.rs @@ -0,0 +1,748 @@ +// Copyright (C) 2025 Stacks Open Internet Foundation +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +/// This file implements the cost functions from costs.clar in Rust. +use super::cost_functions::{linear, logn, nlogn, CostValues}; +use super::ExecutionCost; +use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; + +pub struct Costs1; + +impl CostValues for Costs1 { + fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_type_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_visit(_n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_option_cons(_n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_analysis_option_check(_n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(logn(n, 1000, 1000)?)) + } + + fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 1000, 1000)?)) + } + + fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_check_let(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_lookup_function(_n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_lookup_variable_const(_n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 1000, 1000)?)) + } + + fn cost_ast_parse(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 10000, 1000))) + } + + fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_storage(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: linear(n, 1, 1), + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 0))) + } + + fn cost_lookup_function(_n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_bind_name(_n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_user_function_application(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_let(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_if(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_asserts(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_map(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_filter(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_len(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_element_at(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_index_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_fold(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_list_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_type_parse_step(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_tuple_get(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 1000, 1000)?)) + } + + fn cost_tuple_merge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_tuple_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 1000, 1000)?)) + } + + fn cost_add(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_sub(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_mul(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_div(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_geq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_leq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_le(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_ge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_int_cast(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_mod(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_pow(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_sqrti(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_log2(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_xor(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_not(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_eq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_begin(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_hash160(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_sha256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_sha512(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_sha512t256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_keccak256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_secp256k1recover(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_secp256k1verify(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_print(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_some_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_ok_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_err_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_default_to(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_unwrap_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_is_okay(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_is_none(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_is_err(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_is_some(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_unwrap(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_unwrap_err(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_try_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_match(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_or(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_and(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_append(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_concat(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_as_max_len(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_contract_call(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_contract_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_principal_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1000)) + } + + fn cost_at_block(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_load_contract(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 0, + write_count: 0, + // set to 3 because of the associated metadata loads + read_count: 3, + read_length: linear(n, 1, 1), + }) + } + + fn cost_create_map(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: linear(n, 1, 1), + write_count: 2, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_nft(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_ft(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 1, + write_count: 2, + read_count: 0, + read_length: 0, + }) + } + + fn cost_fetch_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_set_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 0, + }) + } + + fn cost_fetch_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_set_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 0, + }) + } + + fn cost_contract_storage(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_block_info(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_balance(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_mint(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_ft_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_ft_balance(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_mint(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_owner(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_get_supply(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_burn(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_nft_burn(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn poison_microblock(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1000, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_buff_to_int_le(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_int_be(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_is_standard(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_principal_destruct(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_principal_construct(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_string_to_int(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_string_to_uint(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_int_to_ascii(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_int_to_utf8(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_burn_block_info(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_stx_account(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_slice(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_to_consensus_buff(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_from_consensus_buff(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_replace_at(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_as_contract(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_and(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_or(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_not(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } +} diff --git a/clarity/src/vm/costs/costs_2.rs b/clarity/src/vm/costs/costs_2.rs new file mode 100644 index 0000000000..d3d1115970 --- /dev/null +++ b/clarity/src/vm/costs/costs_2.rs @@ -0,0 +1,748 @@ +// Copyright (C) 2025 Stacks Open Internet Foundation +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +/// This file implements the cost functions from costs-2.clar in Rust. +use super::cost_functions::{linear, logn, nlogn, CostValues}; +use super::ExecutionCost; +use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; + +pub struct Costs2; + +impl CostValues for Costs2 { + fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 9))) + } + + fn cost_analysis_type_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 113, 1))) + } + + fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 6))) + } + + fn cost_analysis_visit(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1)) + } + + fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 14))) + } + + fn cost_analysis_option_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(6)) + } + + fn cost_analysis_option_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(3)) + } + + fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 176))) + } + + fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 4))) + } + + fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(logn(n, 1, 2)?)) + } + + fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 3, 5)?)) + } + + fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 59))) + } + + fn cost_analysis_check_let(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 12))) + } + + fn cost_analysis_lookup_function(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(20)) + } + + fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 28))) + } + + fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(15)) + } + + fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 1, 34)?)) + } + + fn cost_ast_parse(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 172, 287441))) + } + + fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 141, 72))) + } + + fn cost_analysis_storage(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 2, 100), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 723), + write_length: linear(n, 1, 1), + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 81, 1303), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 14))) + } + + fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 1))) + } + + fn cost_lookup_function(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(16)) + } + + fn cost_bind_name(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(256)) + } + + fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 9))) + } + + fn cost_user_function_application(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 26, 140))) + } + + fn cost_let(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 146, 862))) + } + + fn cost_if(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(200)) + } + + fn cost_asserts(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_map(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1210, 3314))) + } + + fn cost_filter(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(460)) + } + + fn cost_len(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(486)) + } + + fn cost_element_at(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(619)) + } + + fn cost_index_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 243))) + } + + fn cost_fold(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(483)) + } + + fn cost_list_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 198))) + } + + fn cost_type_parse_step(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(5)) + } + + fn cost_tuple_get(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 4, 1780)?)) + } + + fn cost_tuple_merge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 4, 646))) + } + + fn cost_tuple_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 11, 1101)?)) + } + + fn cost_add(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 157))) + } + + fn cost_sub(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 157))) + } + + fn cost_mul(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 157))) + } + + fn cost_div(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 157))) + } + + fn cost_geq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_leq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_le(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_ge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_int_cast(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_mod(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_pow(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_sqrti(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_log2(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_xor(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_not(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_eq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 7, 172))) + } + + fn cost_begin(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(202)) + } + + fn cost_hash160(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 201))) + } + + fn cost_sha256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 100))) + } + + fn cost_sha512(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 176))) + } + + fn cost_sha512t256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 188))) + } + + fn cost_keccak256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 221))) + } + + fn cost_secp256k1recover(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(14344)) + } + + fn cost_secp256k1verify(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(13540)) + } + + fn cost_print(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 3, 1413))) + } + + fn cost_some_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(230)) + } + + fn cost_ok_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(230)) + } + + fn cost_err_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(230)) + } + + fn cost_default_to(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_unwrap_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(339)) + } + + fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(339)) + } + + fn cost_is_okay(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_is_none(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_is_err(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_is_some(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_unwrap(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_unwrap_err(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_try_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_match(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_or(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 3, 149))) + } + + fn cost_and(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 3, 149))) + } + + fn cost_append(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 71, 176))) + } + + fn cost_concat(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 75, 244))) + } + + fn cost_as_max_len(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(475)) + } + + fn cost_contract_call(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(153)) + } + + fn cost_contract_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(13400)) + } + + fn cost_principal_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(999)) + } + + fn cost_at_block(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 210, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_load_contract(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 157), + write_length: 0, + write_count: 0, + // set to 3 because of the associated metadata loads + read_count: 3, + read_length: linear(n, 1, 1), + }) + } + + fn cost_create_map(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1631), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 7, 2152), + write_length: linear(n, 1, 1), + write_count: 2, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_nft(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1610), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_ft(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1972, + write_length: 1, + write_count: 2, + read_count: 0, + read_length: 0, + }) + } + + fn cost_fetch_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1539), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_set_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 4, 2204), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 0, + }) + } + + fn cost_fetch_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 543), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_set_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 5, 691), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 0, + }) + } + + fn cost_contract_storage(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 13, 7982), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_block_info(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 6321, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_balance(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1385, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1430, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_mint(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1645, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_ft_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 612, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_ft_balance(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 547, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_mint(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_owner(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_get_supply(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 483, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_burn(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 612, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_nft_burn(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn poison_microblock(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 29568, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_buff_to_int_le(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_int_be(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_is_standard(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_principal_destruct(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_principal_construct(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_string_to_int(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_string_to_uint(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_int_to_ascii(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_int_to_utf8(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_burn_block_info(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_stx_account(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_slice(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_to_consensus_buff(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_from_consensus_buff(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_replace_at(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_as_contract(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_and(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_or(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_not(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } +} diff --git a/clarity/src/vm/costs/costs_2_testnet.rs b/clarity/src/vm/costs/costs_2_testnet.rs new file mode 100644 index 0000000000..e6fc3486bf --- /dev/null +++ b/clarity/src/vm/costs/costs_2_testnet.rs @@ -0,0 +1,748 @@ +// Copyright (C) 2025 Stacks Open Internet Foundation +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +/// This file implements the cost functions from costs-2-testnet.clar in Rust. +use super::cost_functions::{linear, logn, nlogn, CostValues}; +use super::ExecutionCost; +use crate::vm::errors::{InterpreterResult, RuntimeErrorType}; + +pub struct Costs2Testnet; + +impl CostValues for Costs2Testnet { + fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 9))) + } + + fn cost_analysis_type_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 113, 1))) + } + + fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 6))) + } + + fn cost_analysis_visit(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1)) + } + + fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 14))) + } + + fn cost_analysis_option_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(6)) + } + + fn cost_analysis_option_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(3)) + } + + fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 176))) + } + + fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 4))) + } + + fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(logn(n, 1, 2)?)) + } + + fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1000, 1000))) + } + + fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 3, 5)?)) + } + + fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 59))) + } + + fn cost_analysis_check_let(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 12))) + } + + fn cost_analysis_lookup_function(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(20)) + } + + fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 28))) + } + + fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(15)) + } + + fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 1, 34)?)) + } + + fn cost_ast_parse(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 172, 287441))) + } + + fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 141, 72))) + } + + fn cost_analysis_storage(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 2, 100), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 723), + write_length: linear(n, 1, 1), + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 81, 1303), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1000, 1000), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 14))) + } + + fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 1))) + } + + fn cost_lookup_function(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(16)) + } + + fn cost_bind_name(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(256)) + } + + fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 9))) + } + + fn cost_user_function_application(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 26, 140))) + } + + fn cost_let(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 146, 862))) + } + + fn cost_if(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(200)) + } + + fn cost_asserts(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(158)) + } + + fn cost_map(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1210, 3314))) + } + + fn cost_filter(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(460)) + } + + fn cost_len(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(486)) + } + + fn cost_element_at(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(619)) + } + + fn cost_index_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 243))) + } + + fn cost_fold(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(483)) + } + + fn cost_list_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 198))) + } + + fn cost_type_parse_step(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(5)) + } + + fn cost_tuple_get(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 4, 1780)?)) + } + + fn cost_tuple_merge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 4, 646))) + } + + fn cost_tuple_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 11, 1101)?)) + } + + fn cost_add(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 12, 156))) + } + + fn cost_sub(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 12, 156))) + } + + fn cost_mul(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 157))) + } + + fn cost_div(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 157))) + } + + fn cost_geq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(166)) + } + + fn cost_leq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(166)) + } + + fn cost_le(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(166)) + } + + fn cost_ge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(166)) + } + + fn cost_int_cast(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(164)) + } + + fn cost_mod(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(168)) + } + + fn cost_pow(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(170)) + } + + fn cost_sqrti(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(167)) + } + + fn cost_log2(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(161)) + } + + fn cost_xor(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(167)) + } + + fn cost_not(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(162)) + } + + fn cost_eq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 7, 172))) + } + + fn cost_begin(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(202)) + } + + fn cost_hash160(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 201))) + } + + fn cost_sha256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 100))) + } + + fn cost_sha512(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 176))) + } + + fn cost_sha512t256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 188))) + } + + fn cost_keccak256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 221))) + } + + fn cost_secp256k1recover(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(14344)) + } + + fn cost_secp256k1verify(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(13540)) + } + + fn cost_print(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 3, 1413))) + } + + fn cost_some_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(230)) + } + + fn cost_ok_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(230)) + } + + fn cost_err_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(230)) + } + + fn cost_default_to(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(249)) + } + + fn cost_unwrap_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(299)) + } + + fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(339)) + } + + fn cost_is_okay(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_is_none(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_is_err(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_is_some(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(287)) + } + + fn cost_unwrap(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(284)) + } + + fn cost_unwrap_err(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(264)) + } + + fn cost_try_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(256)) + } + + fn cost_match(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(286)) + } + + fn cost_or(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 3, 149))) + } + + fn cost_and(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 3, 149))) + } + + fn cost_append(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 71, 176))) + } + + fn cost_concat(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 75, 244))) + } + + fn cost_as_max_len(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(475)) + } + + fn cost_contract_call(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(153)) + } + + fn cost_contract_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(13400)) + } + + fn cost_principal_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(39)) + } + + fn cost_at_block(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 210, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_load_contract(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 157), + write_length: 0, + write_count: 0, + // set to 3 because of the associated metadata loads + read_count: 3, + read_length: linear(n, 1, 1), + }) + } + + fn cost_create_map(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1631), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 7, 2152), + write_length: linear(n, 1, 1), + write_count: 2, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_nft(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1610), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_ft(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1972, + write_length: 1, + write_count: 2, + read_count: 0, + read_length: 0, + }) + } + + fn cost_fetch_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1539), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_set_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 4, 2204), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 0, + }) + } + + fn cost_fetch_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 543), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_set_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 5, 691), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 0, + }) + } + + fn cost_contract_storage(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 13, 7982), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_block_info(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 6321, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_balance(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1385, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1430, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_mint(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1645, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_ft_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 612, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_ft_balance(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 547, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_mint(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_owner(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_get_supply(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 483, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_burn(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 612, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_nft_burn(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn poison_microblock(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 29568, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_buff_to_int_le(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_int_be(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_is_standard(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_principal_destruct(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_principal_construct(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_string_to_int(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_string_to_uint(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_int_to_ascii(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_int_to_utf8(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_burn_block_info(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_stx_account(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_slice(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_to_consensus_buff(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_from_consensus_buff(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_replace_at(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_as_contract(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_and(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_or(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_not(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } + + fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { + Err(RuntimeErrorType::NotImplemented.into()) + } +} diff --git a/clarity/src/vm/costs/costs_3.rs b/clarity/src/vm/costs/costs_3.rs new file mode 100644 index 0000000000..46e5dd0be0 --- /dev/null +++ b/clarity/src/vm/costs/costs_3.rs @@ -0,0 +1,766 @@ +// Copyright (C) 2025 Stacks Open Internet Foundation +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +/// This file implements the cost functions from costs-3.clar in Rust. +use super::cost_functions::{linear, logn, nlogn, CostValues}; +use super::ExecutionCost; +use crate::vm::errors::InterpreterResult; + +pub struct Costs3; + +impl CostValues for Costs3 { + fn cost_analysis_type_annotate(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 9))) + } + + fn cost_analysis_type_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 113, 1))) + } + + fn cost_analysis_type_lookup(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 4))) + } + + fn cost_analysis_visit(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(1)) + } + + fn cost_analysis_iterable_func(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 14))) + } + + fn cost_analysis_option_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(5)) + } + + fn cost_analysis_option_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(4)) + } + + fn cost_analysis_bind_name(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 59))) + } + + fn cost_analysis_list_items_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 4))) + } + + fn cost_analysis_check_tuple_get(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(logn(n, 1, 2)?)) + } + + fn cost_analysis_check_tuple_merge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 45, 49)?)) + } + + fn cost_analysis_check_tuple_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 3, 5)?)) + } + + fn cost_analysis_tuple_items_check(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 28))) + } + + fn cost_analysis_check_let(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 10))) + } + + fn cost_analysis_lookup_function(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(18)) + } + + fn cost_analysis_lookup_function_types(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 26))) + } + + fn cost_analysis_lookup_variable_const(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(15)) + } + + fn cost_analysis_lookup_variable_depth(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 1, 12)?)) + } + + fn cost_ast_parse(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 27, 81))) + } + + fn cost_ast_cycle_detection(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 141, 72))) + } + + fn cost_analysis_storage(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 2, 94), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_analysis_use_trait_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 698), + write_length: linear(n, 1, 1), + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_analysis_fetch_contract_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1516), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_analysis_get_function_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 78, 1307), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_lookup_variable_depth(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 1))) + } + + fn cost_lookup_variable_size(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 1))) + } + + fn cost_lookup_function(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(16)) + } + + fn cost_bind_name(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(216)) + } + + fn cost_inner_type_check_cost(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 2, 5))) + } + + fn cost_user_function_application(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 26, 5))) + } + + fn cost_let(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 117, 178))) + } + + fn cost_if(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(168)) + } + + fn cost_asserts(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(128)) + } + + fn cost_map(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1198, 3067))) + } + + fn cost_filter(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(407)) + } + + fn cost_len(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(429)) + } + + fn cost_element_at(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(498)) + } + + fn cost_index_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 211))) + } + + fn cost_fold(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(460)) + } + + fn cost_list_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 14, 164))) + } + + fn cost_type_parse_step(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(4)) + } + + fn cost_tuple_get(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 4, 1736)?)) + } + + fn cost_tuple_merge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 4, 408))) + } + + fn cost_tuple_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 10, 1876)?)) + } + + fn cost_add(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 11, 125))) + } + + fn cost_sub(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 11, 125))) + } + + fn cost_mul(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 13, 125))) + } + + fn cost_div(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 13, 125))) + } + + fn cost_geq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 7, 128))) + } + + fn cost_leq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 7, 128))) + } + + fn cost_le(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 7, 128))) + } + + fn cost_ge(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 7, 128))) + } + + fn cost_int_cast(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(135)) + } + + fn cost_mod(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(141)) + } + + fn cost_pow(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(143)) + } + + fn cost_sqrti(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(142)) + } + + fn cost_log2(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(133)) + } + + fn cost_xor(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 15, 129))) + } + + fn cost_not(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(138)) + } + + fn cost_eq(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 7, 151))) + } + + fn cost_begin(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(151)) + } + + fn cost_hash160(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 188))) + } + + fn cost_sha256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 100))) + } + + fn cost_sha512(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 176))) + } + + fn cost_sha512t256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 56))) + } + + fn cost_keccak256(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 127))) + } + + fn cost_secp256k1recover(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(8655)) + } + + fn cost_secp256k1verify(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(8349)) + } + + fn cost_print(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 15, 1458))) + } + + fn cost_some_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(199)) + } + + fn cost_ok_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(199)) + } + + fn cost_err_cons(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(199)) + } + + fn cost_default_to(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(268)) + } + + fn cost_unwrap_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(274)) + } + + fn cost_unwrap_err_or_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(302)) + } + + fn cost_is_okay(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(258)) + } + + fn cost_is_none(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(214)) + } + + fn cost_is_err(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(245)) + } + + fn cost_is_some(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(195)) + } + + fn cost_unwrap(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(252)) + } + + fn cost_unwrap_err(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(248)) + } + + fn cost_try_ret(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(240)) + } + + fn cost_match(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(264)) + } + + fn cost_or(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 3, 120))) + } + + fn cost_and(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 3, 120))) + } + + fn cost_append(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 73, 285))) + } + + fn cost_concat(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 37, 220))) + } + + fn cost_as_max_len(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(475)) + } + + fn cost_contract_call(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(134)) + } + + fn cost_contract_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(13400)) + } + + fn cost_principal_of(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(984)) + } + + fn cost_at_block(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1327, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_load_contract(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 80), + write_length: 0, + write_count: 0, + // set to 3 because of the associated metadata loads + read_count: 3, + read_length: linear(n, 1, 1), + }) + } + + fn cost_create_map(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1564), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 7, 2025), + write_length: linear(n, 1, 1), + write_count: 2, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_nft(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1570), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_create_ft(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1831, + write_length: 1, + write_count: 2, + read_count: 0, + read_length: 0, + }) + } + + fn cost_fetch_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 1025), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_set_entry(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 4, 1899), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 0, + }) + } + + fn cost_fetch_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 1, 468), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: linear(n, 1, 1), + }) + } + + fn cost_set_var(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 5, 655), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 1, + read_length: 0, + }) + } + + fn cost_contract_storage(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 11, 7165), + write_length: linear(n, 1, 1), + write_count: 1, + read_count: 0, + read_length: 0, + }) + } + + fn cost_block_info(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 6321, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_balance(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 4294, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 4640, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_mint(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 1479, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_ft_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 549, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_ft_balance(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 479, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_mint(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 575), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_transfer(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 572), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_nft_owner(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 795), + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_get_supply(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 420, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_ft_burn(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 549, + write_length: 1, + write_count: 2, + read_count: 2, + read_length: 1, + }) + } + + fn cost_nft_burn(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: linear(n, 9, 572), + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn poison_microblock(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 17485, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_buff_to_int_le(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(141)) + } + + fn cost_buff_to_uint_le(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(141)) + } + + fn cost_buff_to_int_be(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(141)) + } + + fn cost_buff_to_uint_be(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(141)) + } + + fn cost_is_standard(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(127)) + } + + fn cost_principal_destruct(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(314)) + } + + fn cost_principal_construct(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(398)) + } + + fn cost_string_to_int(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(168)) + } + + fn cost_string_to_uint(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(168)) + } + + fn cost_int_to_ascii(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(147)) + } + + fn cost_int_to_utf8(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(181)) + } + + fn cost_burn_block_info(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 96479, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_stx_account(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 4654, + write_length: 0, + write_count: 0, + read_count: 1, + read_length: 1, + }) + } + + fn cost_slice(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(448)) + } + + fn cost_to_consensus_buff(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 233))) + } + + fn cost_from_consensus_buff(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(nlogn(n, 3, 185)?)) + } + + fn cost_stx_transfer_memo(n: u64) -> InterpreterResult { + Ok(ExecutionCost { + runtime: 4709, + write_length: 1, + write_count: 1, + read_count: 1, + read_length: 1, + }) + } + + fn cost_replace_at(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 1, 561))) + } + + fn cost_as_contract(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(138)) + } + + fn cost_bitwise_and(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 15, 129))) + } + + fn cost_bitwise_or(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(linear(n, 15, 129))) + } + + fn cost_bitwise_not(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(147)) + } + + fn cost_bitwise_left_shift(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(167)) + } + + fn cost_bitwise_right_shift(n: u64) -> InterpreterResult { + Ok(ExecutionCost::runtime(167)) + } +} diff --git a/clarity/src/vm/costs/mod.rs b/clarity/src/vm/costs/mod.rs index d86cd643bd..3f8353ad07 100644 --- a/clarity/src/vm/costs/mod.rs +++ b/clarity/src/vm/costs/mod.rs @@ -16,11 +16,16 @@ use std::{cmp, fmt}; +use costs_1::Costs1; +use costs_2::Costs2; +use costs_2_testnet::Costs2Testnet; +use costs_3::Costs3; use hashbrown::HashMap; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use stacks_common::types::StacksEpochId; +use super::errors::{CheckErrors, RuntimeErrorType}; use crate::boot_util::boot_code_id; use crate::vm::contexts::{ContractContext, GlobalContext}; use crate::vm::costs::cost_functions::ClarityCostFunction; @@ -37,6 +42,14 @@ use crate::vm::{eval_all, ClarityName, SymbolicExpression, Value}; pub mod constants; pub mod cost_functions; +#[allow(unused_variables)] +pub mod costs_1; +#[allow(unused_variables)] +pub mod costs_2; +#[allow(unused_variables)] +pub mod costs_2_testnet; +#[allow(unused_variables)] +pub mod costs_3; type Result = std::result::Result; @@ -171,6 +184,80 @@ impl ::std::fmt::Display for ClarityCostFunctionReference { } } +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Copy)] +pub enum DefaultVersion { + Costs1, + Costs2, + Costs2Testnet, + Costs3, +} + +impl DefaultVersion { + pub fn evaluate( + &self, + cost_function_ref: &ClarityCostFunctionReference, + f: &ClarityCostFunction, + input: &[u64], + ) -> Result { + let n = input.first().ok_or_else(|| { + CostErrors::Expect("Default cost function supplied with 0 args".into()) + })?; + let r = match self { + DefaultVersion::Costs1 => f.eval::(*n), + DefaultVersion::Costs2 => f.eval::(*n), + DefaultVersion::Costs2Testnet => f.eval::(*n), + DefaultVersion::Costs3 => f.eval::(*n), + }; + r.map_err(|e| { + let e = match e { + crate::vm::errors::Error::Runtime(RuntimeErrorType::NotImplemented, _) => { + CheckErrors::UndefinedFunction(cost_function_ref.function_name.clone()).into() + } + other => other, + }; + + CostErrors::CostComputationFailed(format!( + "Error evaluating result of cost function {}: {e}", + &cost_function_ref.function_name + )) + }) + } +} + +impl DefaultVersion { + pub fn try_from( + mainnet: bool, + value: &QualifiedContractIdentifier, + ) -> std::result::Result { + if !value.is_boot() { + return Err("Not a boot contract".into()); + } + if value.name.as_str() == COSTS_1_NAME { + Ok(Self::Costs1) + } else if value.name.as_str() == COSTS_2_NAME { + if mainnet { + Ok(Self::Costs2) + } else { + Ok(Self::Costs2Testnet) + } + } else if value.name.as_str() == COSTS_3_NAME { + Ok(Self::Costs3) + } else { + Err(format!("Unknown default contract {}", &value.name)) + } + } +} + +#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] +pub enum ClarityCostFunctionEvaluator { + Default( + ClarityCostFunctionReference, + ClarityCostFunction, + DefaultVersion, + ), + Clarity(ClarityCostFunctionReference), +} + impl ClarityCostFunctionReference { fn new(id: QualifiedContractIdentifier, name: String) -> ClarityCostFunctionReference { ClarityCostFunctionReference { @@ -234,7 +321,7 @@ impl CostStateSummary { #[derive(Clone)] /// This struct holds all of the data required for non-free LimitedCostTracker instances pub struct TrackerData { - cost_function_references: HashMap<&'static ClarityCostFunction, ClarityCostFunctionReference>, + cost_function_references: HashMap<&'static ClarityCostFunction, ClarityCostFunctionEvaluator>, cost_contracts: HashMap, contract_call_circuits: HashMap<(QualifiedContractIdentifier, ClarityName), ClarityCostFunctionReference>, @@ -272,7 +359,7 @@ impl LimitedCostTracker { } pub fn cost_function_references( &self, - ) -> HashMap<&'static ClarityCostFunction, ClarityCostFunctionReference> { + ) -> HashMap<&'static ClarityCostFunction, ClarityCostFunctionEvaluator> { match self { Self::Free => panic!("Cannot get cost function references on free tracker"), Self::Limited(TrackerData { @@ -757,7 +844,7 @@ impl LimitedCostTracker { Self::Free } - fn default_cost_contract_for_epoch(epoch_id: StacksEpochId) -> Result { + pub fn default_cost_contract_for_epoch(epoch_id: StacksEpochId) -> Result { let result = match epoch_id { StacksEpochId::Epoch10 => { return Err(CostErrors::Expect("Attempted to get default cost functions for Epoch 1.0 where Clarity does not exist".into())); @@ -792,6 +879,12 @@ impl TrackerData { self.mainnet, ); + let v = DefaultVersion::try_from(self.mainnet, &boot_costs_id).map_err(|e| { + CostErrors::Expect(format!( + "Failed to get version of default costs contract {e}" + )) + })?; + let CostStateSummary { contract_call_circuits, mut cost_function_references, @@ -811,6 +904,7 @@ impl TrackerData { let iter_len = iter.len(); let mut cost_contracts = HashMap::with_capacity(iter_len); let mut m = HashMap::with_capacity(iter_len); + for f in iter { let cost_function_ref = cost_function_references.remove(f).unwrap_or_else(|| { ClarityCostFunctionReference::new(boot_costs_id.clone(), f.get_name()) @@ -832,7 +926,14 @@ impl TrackerData { cost_contracts.insert(cost_function_ref.contract_id.clone(), contract_context); } - m.insert(f, cost_function_ref); + if cost_function_ref.contract_id == boot_costs_id { + m.insert( + f, + ClarityCostFunctionEvaluator::Default(cost_function_ref, *f, v), + ); + } else { + m.insert(f, ClarityCostFunctionEvaluator::Clarity(cost_function_ref)); + } } for (_, circuit_target) in self.contract_call_circuits.iter() { @@ -906,7 +1007,7 @@ impl LimitedCostTracker { } } -fn parse_cost( +pub fn parse_cost( cost_function_name: &str, eval_result: InterpreterResult>, ) -> Result { @@ -928,11 +1029,11 @@ fn parse_cost( Some(UInt(read_length)), Some(UInt(read_count)), ) => Ok(ExecutionCost { - write_length: (*write_length as u64), - write_count: (*write_count as u64), - runtime: (*runtime as u64), - read_length: (*read_length as u64), - read_count: (*read_count as u64), + write_length: (*write_length).try_into().unwrap_or(u64::MAX), + write_count: (*write_count).try_into().unwrap_or(u64::MAX), + runtime: (*runtime).try_into().unwrap_or(u64::MAX), + read_length: (*read_length).try_into().unwrap_or(u64::MAX), + read_count: (*read_count).try_into().unwrap_or(u64::MAX), }), _ => Err(CostErrors::CostComputationFailed( "Execution Cost tuple does not contain only UInts".to_string(), @@ -946,8 +1047,7 @@ fn parse_cost( "Clarity cost function returned nothing".to_string(), )), Err(e) => Err(CostErrors::CostComputationFailed(format!( - "Error evaluating result of cost function {}: {}", - cost_function_name, e + "Error evaluating result of cost function {cost_function_name}: {e}" ))), } } @@ -1051,15 +1151,22 @@ impl CostTracker for LimitedCostTracker { "Used unimplemented cost function".into(), )); } - let cost_function_ref = data - .cost_function_references - .get(&cost_function) - .ok_or(CostErrors::CostComputationFailed(format!( + let cost_function_ref = data.cost_function_references.get(&cost_function).ok_or( + CostErrors::CostComputationFailed(format!( "CostFunction not defined: {cost_function}" - )))? - .clone(); - - compute_cost(data, cost_function_ref, input, data.epoch) + )), + )?; + + match cost_function_ref { + ClarityCostFunctionEvaluator::Default( + cost_function_ref, + clarity_cost_function, + default_version, + ) => default_version.evaluate(cost_function_ref, clarity_cost_function, input), + ClarityCostFunctionEvaluator::Clarity(cost_function_ref) => { + compute_cost(data, cost_function_ref.clone(), input, data.epoch) + } + } } } } @@ -1227,10 +1334,7 @@ impl ExecutionCost { * 1_f64.min(self.write_length as f64 / 1_f64.max(block_limit.write_length as f64)), ] .iter() - .fold(0, |acc, dim| { - acc.checked_add(cmp::max(*dim as u64, 1)) - .unwrap_or(u64::MAX) - }) + .fold(0, |acc, dim| acc.saturating_add(cmp::max(*dim as u64, 1))) } pub fn max_value() -> ExecutionCost { diff --git a/stackslib/src/chainstate/nakamoto/mod.rs b/stackslib/src/chainstate/nakamoto/mod.rs index 056bd53fe4..c5df44c618 100644 --- a/stackslib/src/chainstate/nakamoto/mod.rs +++ b/stackslib/src/chainstate/nakamoto/mod.rs @@ -2578,6 +2578,18 @@ impl NakamotoChainState { .map_err(ChainstateError::from) } + /// Return the ExecutionCost of `block` + pub fn get_block_cost( + chainstate_conn: &Connection, + block: &StacksBlockId, + ) -> Result, ChainstateError> { + let qry = "SELECT total_tenure_cost FROM nakamoto_block_headers WHERE index_block_hash = ?"; + chainstate_conn + .query_row(qry, &[block], |row| row.get(0)) + .optional() + .map_err(ChainstateError::from) + } + /// Return the total transactions fees during the tenure up to and including /// `block` pub fn get_total_tenure_tx_fees_at( diff --git a/stackslib/src/chainstate/stacks/miner.rs b/stackslib/src/chainstate/stacks/miner.rs index 9e5fd383b9..819de80a33 100644 --- a/stackslib/src/chainstate/stacks/miner.rs +++ b/stackslib/src/chainstate/stacks/miner.rs @@ -16,6 +16,8 @@ use std::collections::{HashMap, HashSet}; use std::sync::atomic::{AtomicBool, Ordering}; +#[cfg(any(test, feature = "testing"))] +use std::sync::LazyLock; use std::sync::{Arc, Mutex}; use std::thread::ThreadId; use std::time::Instant; @@ -37,6 +39,8 @@ use stacks_common::types::StacksPublicKeyBuffer; use stacks_common::util::get_epoch_time_ms; use stacks_common::util::hash::{MerkleTree, Sha512Trunc256Sum}; use stacks_common::util::secp256k1::{MessageSignature, Secp256k1PrivateKey}; +#[cfg(any(test, feature = "testing"))] +use stacks_common::util::tests::TestFlag; use stacks_common::util::vrf::*; use crate::burnchains::{Burnchain, PrivateKey, PublicKey}; @@ -67,6 +71,26 @@ use crate::monitoring::{ use crate::net::relay::Relayer; use crate::net::Error as net_error; +#[cfg(any(test, feature = "testing"))] +/// Test flag to stall transaction execution +pub static TEST_TX_STALL: LazyLock> = LazyLock::new(TestFlag::default); + +/// Stall transaction processing for testing +#[cfg(any(test, feature = "testing"))] +fn fault_injection_stall_tx() { + if TEST_TX_STALL.get() { + // Do an extra check just so we don't log EVERY time. + warn!("Tx is stalled due to testing directive"); + while TEST_TX_STALL.get() { + std::thread::sleep(std::time::Duration::from_millis(10)); + } + warn!("Tx is no longer stalled due to testing directive. Continuing..."); + } +} + +#[cfg(not(any(test, feature = "testing")))] +fn fault_injection_stall_tx() {} + /// Fully-assembled Stacks anchored, block as well as some extra metadata pertaining to how it was /// linked to the burnchain and what view(s) the miner had of the burnchain before and after /// completing the block. @@ -2374,6 +2398,9 @@ impl StacksBlockBuilder { num_considered += 1; let tx_start = Instant::now(); + + fault_injection_stall_tx(); + let tx_result = builder.try_mine_tx_with_len( epoch_tx, &txinfo.tx, diff --git a/stackslib/src/clarity_vm/tests/costs.rs b/stackslib/src/clarity_vm/tests/costs.rs index 400d5c34b7..ea85bbf0f1 100644 --- a/stackslib/src/clarity_vm/tests/costs.rs +++ b/stackslib/src/clarity_vm/tests/costs.rs @@ -23,7 +23,10 @@ use clarity::vm::contexts::{ }; use clarity::vm::contracts::Contract; use clarity::vm::costs::cost_functions::ClarityCostFunction; -use clarity::vm::costs::{ClarityCostFunctionReference, ExecutionCost, LimitedCostTracker}; +use clarity::vm::costs::{ + parse_cost, ClarityCostFunctionEvaluator, ClarityCostFunctionReference, CostErrors, + DefaultVersion, ExecutionCost, LimitedCostTracker, COSTS_1_NAME, COSTS_2_NAME, COSTS_3_NAME, +}; use clarity::vm::database::{ClarityDatabase, MemoryBackingStore}; use clarity::vm::errors::{CheckErrors, Error, RuntimeErrorType}; use clarity::vm::events::StacksTransactionEvent; @@ -873,6 +876,84 @@ fn setup_cost_tracked_test( .unwrap(); } +fn eval_cost_fn( + owned_env: &mut OwnedEnvironment, + cost_contract_name: &str, + cost_fn: &ClarityCostFunction, + argument: u64, +) -> Result { + let mainnet = owned_env.is_mainnet(); + let boot_costs_id = boot_code_id(cost_contract_name, mainnet); + let cost_fn_name = cost_fn.get_name_str(); + + let exec = format!("({cost_fn_name} u{argument})"); + + let exec_result = owned_env + .eval_read_only(&boot_costs_id, &exec) + .map(|(value, _, _)| Some(value)); + + parse_cost(cost_fn_name, exec_result) +} + +fn eval_replaced_cost_fn( + owned_env: &mut OwnedEnvironment, + cost_contract_name: &str, + cost_fn: &ClarityCostFunction, + argument: u64, +) -> Result { + let mainnet = owned_env.is_mainnet(); + let boot_costs_id = boot_code_id(cost_contract_name, mainnet); + let clarity_cost_fn_default_version = DefaultVersion::try_from(mainnet, &boot_costs_id) + .expect("FAIL: should find default version for boot cost contracts"); + let cost_fn_name = cost_fn.get_name_str(); + let clarity_cost_fn_ref = ClarityCostFunctionReference { + contract_id: boot_costs_id, + function_name: cost_fn_name.to_string(), + }; + clarity_cost_fn_default_version.evaluate(&clarity_cost_fn_ref, cost_fn, &[argument]) +} + +fn proptest_cost_fn(cost_fn: &ClarityCostFunction, cost_contract_name: &str) { + let mut inputs = vec![0, u64::MAX]; + (1..64).for_each(|i| { + inputs.push(2u64.pow(i) - 1); + inputs.push(2u64.pow(i)); + inputs.push(2u64.pow(i) + 1); + }); + for use_mainnet in [true, false] { + with_owned_env(StacksEpochId::latest(), use_mainnet, |mut owned_env| { + for i in inputs.iter() { + eprintln!("Evaluating {cost_contract_name}.{cost_fn}({i})"); + let clar_evaled = eval_cost_fn(&mut owned_env, cost_contract_name, cost_fn, *i); + let replace_evaled = + eval_replaced_cost_fn(&mut owned_env, cost_contract_name, cost_fn, *i); + assert_eq!(clar_evaled, replace_evaled); + } + }); + } +} + +fn proptest_cost_contract(cost_contract_name: &str) { + for cost_fn in ClarityCostFunction::ALL.iter() { + proptest_cost_fn(cost_fn, cost_contract_name); + } +} + +#[test] +fn proptest_replacements_costs_1() { + proptest_cost_contract(COSTS_1_NAME); +} + +#[test] +fn proptest_replacements_costs_2() { + proptest_cost_contract(COSTS_2_NAME); +} + +#[test] +fn proptest_replacements_costs_3() { + proptest_cost_contract(COSTS_3_NAME); +} + fn test_program_cost( prog: &str, version: ClarityVersion, @@ -1533,14 +1614,11 @@ fn test_cost_voting_integration(use_mainnet: bool, clarity_version: ClarityVersi "No contract call circuits should have been processed" ); for (target, referenced_function) in tracker.cost_function_references().into_iter() { - assert_eq!( - &referenced_function.contract_id, - &boot_code_id("costs", use_mainnet), - "All cost functions should still point to the boot costs" - ); - assert_eq!( - &referenced_function.function_name, - target.get_name_str(), + assert!( + matches!( + referenced_function, + ClarityCostFunctionEvaluator::Default(_, _, DefaultVersion::Costs1) + ), "All cost functions should still point to the boot costs" ); } @@ -1649,17 +1727,19 @@ fn test_cost_voting_integration(use_mainnet: bool, clarity_version: ClarityVersi for (target, referenced_function) in tracker.cost_function_references().into_iter() { if target == &ClarityCostFunction::Le { + let ClarityCostFunctionEvaluator::Clarity(referenced_function) = + referenced_function + else { + panic!("Replaced function should be evaluated in Clarity"); + }; assert_eq!(&referenced_function.contract_id, &cost_definer); assert_eq!(&referenced_function.function_name, "cost-definition-le"); } else { - assert_eq!( - &referenced_function.contract_id, - &boot_code_id("costs", use_mainnet), - "Cost function should still point to the boot costs" - ); - assert_eq!( - &referenced_function.function_name, - target.get_name_str(), + assert!( + matches!( + referenced_function, + ClarityCostFunctionEvaluator::Default(_, _, DefaultVersion::Costs1) + ), "Cost function should still point to the boot costs" ); } diff --git a/stackslib/src/cli.rs b/stackslib/src/cli.rs index f43812f2ba..c51fbe4a85 100644 --- a/stackslib/src/cli.rs +++ b/stackslib/src/cli.rs @@ -47,6 +47,7 @@ use crate::chainstate::stacks::db::{StacksBlockHeaderTypes, StacksChainState, St use crate::chainstate::stacks::miner::*; use crate::chainstate::stacks::{Error as ChainstateError, *}; use crate::clarity_vm::clarity::ClarityInstance; +use crate::clarity_vm::database::GetTenureStartId; use crate::config::{Config, ConfigFile, DEFAULT_MAINNET_CONFIG}; use crate::core::*; use crate::cost_estimates::metrics::UnitMetric; @@ -727,6 +728,13 @@ fn replay_block( }; let parent_block_hash = parent_block_header.block_hash(); + let Some(cost) = + StacksChainState::get_stacks_block_anchored_cost(chainstate_tx.conn(), block_id).unwrap() + else { + println!("No header info found for {block_id}"); + return; + }; + let Some(next_microblocks) = StacksChainState::inner_find_parent_microblock_stream( &chainstate_tx.tx, block_hash, @@ -822,7 +830,13 @@ fn replay_block( block_am.weight(), true, ) { - Ok((_receipt, _, _)) => { + Ok((receipt, _, _)) => { + if receipt.anchored_block_cost != cost { + println!("Failed processing block! block = {block_id}. Unexpected cost. expected = {cost}, evaluated = {}", + receipt.anchored_block_cost); + process::exit(1); + } + info!("Block processed successfully! block = {block_id}"); } Err(e) => { @@ -892,6 +906,33 @@ fn replay_block_nakamoto( "burn_block_hash" => %next_ready_block_snapshot.burn_header_hash ); + let Some(mut expected_total_tenure_cost) = NakamotoChainState::get_total_tenure_cost_at( + stacks_chain_state.db(), + &block.header.block_id(), + ) + .unwrap() else { + println!("Failed to find cost for block {}", block.header.block_id()); + return Ok(()); + }; + + let expected_cost = if block.get_tenure_tx_payload().is_some() { + expected_total_tenure_cost + } else { + let Some(expected_parent_total_tenure_cost) = NakamotoChainState::get_total_tenure_cost_at( + stacks_chain_state.db(), + &block.header.parent_block_id, + ) + .unwrap() else { + println!( + "Failed to find cost for parent of block {}", + block.header.block_id() + ); + return Ok(()); + }; + expected_total_tenure_cost.sub(&expected_parent_total_tenure_cost).expect("FATAL: failed to subtract parent total cost from self total cost in non-tenure-changing block"); + expected_total_tenure_cost + }; + let elected_height = sort_db .get_consensus_hash_height(&block.header.consensus_hash)? .ok_or_else(|| ChainstateError::NoSuchBlockError)?; @@ -1079,7 +1120,7 @@ fn replay_block_nakamoto( // though it will always be None), which gets the borrow-checker to believe that it's safe // to access `stacks_chain_state` again. In the `Ok(..)` case, it's instead sufficient so // simply commit the block before beginning the second transaction to mark it processed. - + let block_id = block.block_id(); let mut burn_view_handle = sort_db.index_handle(&burnchain_view_sn.sortition_id); let (ok_opt, err_opt) = match NakamotoChainState::append_block( &mut chainstate_tx, @@ -1101,13 +1142,21 @@ fn replay_block_nakamoto( &active_reward_set, true, ) { - Ok(next_chain_tip_info) => (Some(next_chain_tip_info), None), + Ok((receipt, _, _, _)) => (Some(receipt), None), Err(e) => (None, Some(e)), }; + if let Some(receipt) = ok_opt { + // check the cost + let evaluated_cost = receipt.anchored_block_cost.clone(); + if evaluated_cost != expected_cost { + println!("Failed processing block! block = {block_id}. Unexpected cost. expected = {expected_cost}, evaluated = {evaluated_cost}"); + process::exit(1); + } + } + if let Some(e) = err_opt { // force rollback - drop(ok_opt); drop(chainstate_tx); warn!( diff --git a/testnet/stacks-node/src/tests/nakamoto_integrations.rs b/testnet/stacks-node/src/tests/nakamoto_integrations.rs index 6aa481b7cb..fc4dabd175 100644 --- a/testnet/stacks-node/src/tests/nakamoto_integrations.rs +++ b/testnet/stacks-node/src/tests/nakamoto_integrations.rs @@ -51,6 +51,7 @@ use stacks::chainstate::stacks::boot::{ use stacks::chainstate::stacks::db::{StacksChainState, StacksHeaderInfo}; use stacks::chainstate::stacks::miner::{ BlockBuilder, BlockLimitFunction, TransactionEvent, TransactionResult, TransactionSuccessEvent, + TEST_TX_STALL, }; use stacks::chainstate::stacks::{ SinglesigHashMode, SinglesigSpendingCondition, StacksTransaction, TenureChangeCause, @@ -9842,8 +9843,6 @@ fn skip_mining_long_tx() { wait_for_first_naka_block_commit(60, &commits_submitted); // submit a long running TX and the transfer TX - let input_list: Vec<_> = (1..100u64).map(|x| x.to_string()).collect(); - let input_list = input_list.join(" "); // Mine a few nakamoto tenures with some interim blocks in them for i in 0..5 { @@ -9863,27 +9862,23 @@ fn skip_mining_long_tx() { .unwrap(); TEST_P2P_BROADCAST_SKIP.set(true); + TEST_TX_STALL.set(true); let tx = make_contract_publish( &sender_2_sk, 0, 9_000, naka_conf.burnchain.chain_id, "large_contract", - &format!( - "(define-constant INP_LIST (list {input_list})) - (define-private (mapping-fn (input int)) - (begin (sha256 (sha256 (sha256 (sha256 (sha256 (sha256 (sha256 (sha256 (sha256 input))))))))) - 0)) - - (define-private (mapping-fn-2 (input int)) - (begin (map mapping-fn INP_LIST) (map mapping-fn INP_LIST) (map mapping-fn INP_LIST) (map mapping-fn INP_LIST) 0)) - - (begin - (map mapping-fn-2 INP_LIST))" - ), + "(print \"hello world\")", ); submit_tx(&http_origin, &tx); + // Sleep for longer than the miner's attempt time, so that the miner will + // mark this tx as long-running and skip it in the next attempt + sleep_ms(naka_conf.miner.nakamoto_attempt_time_ms + 1000); + + TEST_TX_STALL.set(false); + wait_for(90, || { Ok(mined_naka_blocks.load(Ordering::SeqCst) > mined_before + 1) })