1- // Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation
2- // Copyright (C) 2020 Stacks Open Internet Foundation
3- //
4- // This program is free software: you can redistribute it and/or modify
5- // it under the terms of the GNU General Public License as published by
6- // the Free Software Foundation, either version 3 of the License, or
7- // (at your option) any later version.
8- //
9- // This program is distributed in the hope that it will be useful,
10- // but WITHOUT ANY WARRANTY; without even the implied warranty of
11- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12- // GNU General Public License for more details.
13- //
14- // You should have received a copy of the GNU General Public License
15- // along with this program. If not, see <http://www.gnu.org/licenses/>.
16-
171use std:: collections:: HashMap ;
182
193use rstest:: rstest;
204use stacks_common:: types:: StacksEpochId ;
215
226use crate :: vm:: contexts:: OwnedEnvironment ;
23- use crate :: vm:: costs:: analysis:: { build_cost_analysis_tree, static_cost, UserArgumentsContext } ;
7+ use crate :: vm:: costs:: analysis:: {
8+ build_cost_analysis_tree, static_cost_from_ast, UserArgumentsContext ,
9+ } ;
2410use crate :: vm:: costs:: ExecutionCost ;
2511use crate :: vm:: tests:: { tl_env_factory, TopLevelMemoryEnvironmentGenerator } ;
2612use crate :: vm:: types:: { PrincipalData , QualifiedContractIdentifier } ;
@@ -38,17 +24,23 @@ fn test_simple_trait_implementation_costs(
3824 #[ case] epoch : StacksEpochId ,
3925 mut tl_env_factory : TopLevelMemoryEnvironmentGenerator ,
4026) {
41- // Simple trait implementation - very brief function that basically does nothing
4227 let simple_impl = r#"(impl-trait .mytrait.mytrait)
4328 (define-public (somefunc (a uint) (b uint))
4429 (ok (+ a b))
4530 )"# ;
4631
47- // Set up environment with cost tracking - use regular environment but try to get actual costs
4832 let mut owned_env = tl_env_factory. get_env ( epoch) ;
4933
50- // Get static cost analysis
51- let static_cost = static_cost ( simple_impl, & version) . unwrap ( ) ;
34+ let epoch = StacksEpochId :: Epoch21 ;
35+ let ast = crate :: vm:: ast:: build_ast (
36+ & QualifiedContractIdentifier :: transient ( ) ,
37+ simple_impl,
38+ & mut ( ) ,
39+ version,
40+ epoch,
41+ )
42+ . unwrap ( ) ;
43+ let static_cost = static_cost_from_ast ( & ast, & version) . unwrap ( ) ;
5244 // Deploy and execute the contract to get dynamic costs
5345 let contract_id = QualifiedContractIdentifier :: local ( "simple-impl" ) . unwrap ( ) ;
5446 owned_env
@@ -71,71 +63,13 @@ fn test_simple_trait_implementation_costs(
7163 assert ! ( dynamic_cost. runtime <= cost. max. runtime) ;
7264}
7365
74- /// Helper function to execute a contract function and return the execution cost
75- fn execute_contract_function_and_get_cost (
76- env : & mut OwnedEnvironment ,
77- contract_id : & QualifiedContractIdentifier ,
78- function_name : & str ,
79- args : & [ u64 ] ,
80- version : ClarityVersion ,
81- ) -> ExecutionCost {
82- // Start with a fresh cost tracker
83- let initial_cost = env. get_cost_total ( ) ;
84-
85- // Create a dummy sender
86- let sender = PrincipalData :: parse_qualified_contract_principal (
87- "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sender" ,
88- )
89- . unwrap ( ) ;
90-
91- // Build function call string
92- let arg_str = args
93- . iter ( )
94- . map ( |a| format ! ( "u{}" , a) )
95- . collect :: < Vec < _ > > ( )
96- . join ( " " ) ;
97- let function_call = format ! ( "({} {})" , function_name, arg_str) ;
98-
99- // Parse the function call into a symbolic expression
100- let ast = crate :: vm:: ast:: parse (
101- & QualifiedContractIdentifier :: transient ( ) ,
102- & function_call,
103- version,
104- StacksEpochId :: Epoch21 ,
105- )
106- . expect ( "Failed to parse function call" ) ;
107-
108- if !ast. is_empty ( ) {
109- let _result = env. execute_transaction (
110- sender,
111- None ,
112- contract_id. clone ( ) ,
113- & function_call,
114- & ast[ 0 ..1 ] ,
115- ) ;
116- }
117-
118- // Get the cost after execution
119- let final_cost = env. get_cost_total ( ) ;
120-
121- // Return the difference
122- ExecutionCost {
123- write_length : final_cost. write_length - initial_cost. write_length ,
124- write_count : final_cost. write_count - initial_cost. write_count ,
125- read_length : final_cost. read_length - initial_cost. read_length ,
126- read_count : final_cost. read_count - initial_cost. read_count ,
127- runtime : final_cost. runtime - initial_cost. runtime ,
128- }
129- }
130-
13166#[ rstest]
13267#[ case:: clarity2( ClarityVersion :: Clarity2 , StacksEpochId :: Epoch21 ) ]
13368fn test_complex_trait_implementation_costs (
13469 #[ case] version : ClarityVersion ,
13570 #[ case] epoch : StacksEpochId ,
13671 mut tl_env_factory : TopLevelMemoryEnvironmentGenerator ,
13772) {
138- // Complex trait implementation with expensive operations but no external calls
13973 let complex_impl = r#"(define-public (somefunc (a uint) (b uint))
14074 (begin
14175 ;; do something expensive
@@ -152,7 +86,16 @@ fn test_complex_trait_implementation_costs(
15286
15387 let mut owned_env = tl_env_factory. get_env ( epoch) ;
15488
155- let static_cost_result = static_cost ( complex_impl, & version) ;
89+ let epoch = StacksEpochId :: Epoch21 ;
90+ let ast = crate :: vm:: ast:: build_ast (
91+ & QualifiedContractIdentifier :: transient ( ) ,
92+ complex_impl,
93+ & mut ( ) ,
94+ version,
95+ epoch,
96+ )
97+ . unwrap ( ) ;
98+ let static_cost_result = static_cost_from_ast ( & ast, & version) ;
15699 match static_cost_result {
157100 Ok ( static_cost) => {
158101 let contract_id = QualifiedContractIdentifier :: local ( "complex-impl" ) . unwrap ( ) ;
@@ -228,11 +171,74 @@ fn test_dependent_function_calls() {
228171)"# ;
229172
230173 let contract_id = QualifiedContractIdentifier :: transient ( ) ;
231- let function_map = static_cost ( src, & ClarityVersion :: Clarity3 ) . unwrap ( ) ;
174+ let epoch = StacksEpochId :: Epoch32 ;
175+ let ast = crate :: vm:: ast:: build_ast (
176+ & QualifiedContractIdentifier :: transient ( ) ,
177+ src,
178+ & mut ( ) ,
179+ ClarityVersion :: Clarity3 ,
180+ epoch,
181+ )
182+ . unwrap ( ) ;
183+ let function_map = static_cost_from_ast ( & ast, & ClarityVersion :: Clarity3 ) . unwrap ( ) ;
232184
233185 let add_one_cost = function_map. get ( "add-one" ) . unwrap ( ) ;
234186 let somefunc_cost = function_map. get ( "somefunc" ) . unwrap ( ) ;
235187
236188 assert ! ( add_one_cost. min. runtime >= somefunc_cost. min. runtime) ;
237189 assert ! ( add_one_cost. max. runtime >= somefunc_cost. max. runtime) ;
238190}
191+
192+ /// Helper function to execute a contract function and return the execution cost
193+ fn execute_contract_function_and_get_cost (
194+ env : & mut OwnedEnvironment ,
195+ contract_id : & QualifiedContractIdentifier ,
196+ function_name : & str ,
197+ args : & [ u64 ] ,
198+ version : ClarityVersion ,
199+ ) -> ExecutionCost {
200+ // Start with a fresh cost tracker
201+ let initial_cost = env. get_cost_total ( ) ;
202+
203+ // Create a dummy sender
204+ let sender = PrincipalData :: parse_qualified_contract_principal (
205+ "ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.sender" ,
206+ )
207+ . unwrap ( ) ;
208+
209+ let arg_str = args
210+ . iter ( )
211+ . map ( |a| format ! ( "u{}" , a) )
212+ . collect :: < Vec < _ > > ( )
213+ . join ( " " ) ;
214+ let function_call = format ! ( "({} {})" , function_name, arg_str) ;
215+
216+ let ast = crate :: vm:: ast:: parse (
217+ & QualifiedContractIdentifier :: transient ( ) ,
218+ & function_call,
219+ version,
220+ StacksEpochId :: Epoch21 ,
221+ )
222+ . expect ( "Failed to parse function call" ) ;
223+
224+ if !ast. is_empty ( ) {
225+ let _result = env. execute_transaction (
226+ sender,
227+ None ,
228+ contract_id. clone ( ) ,
229+ & function_call,
230+ & ast[ 0 ..1 ] ,
231+ ) ;
232+ }
233+
234+ // Get the cost after execution
235+ let final_cost = env. get_cost_total ( ) ;
236+
237+ ExecutionCost {
238+ write_length : final_cost. write_length - initial_cost. write_length ,
239+ write_count : final_cost. write_count - initial_cost. write_count ,
240+ read_length : final_cost. read_length - initial_cost. read_length ,
241+ read_count : final_cost. read_count - initial_cost. read_count ,
242+ runtime : final_cost. runtime - initial_cost. runtime ,
243+ }
244+ }
0 commit comments