@@ -97,17 +97,64 @@ const MAX_TOTAL_FUNCTION_PARAMS: usize = 10_000;
97
97
/// during static validation.
98
98
const MAX_FUNCTION_RESULTS : usize = 1 ;
99
99
100
+ #[ derive( Clone , Copy ) ]
101
+ pub enum LogOutput {
102
+ StdOut ,
103
+ StdErr ,
104
+ }
105
+ #[ derive( Clone , Copy , Default ) ]
106
+ pub enum Logger < ' a > {
107
+ On {
108
+ prefix : & ' a str ,
109
+ output : LogOutput ,
110
+ } ,
111
+ #[ default]
112
+ Off ,
113
+ }
114
+
115
+ impl < ' a > Logger < ' a > {
116
+ pub fn with_config ( output : LogOutput , prefix : & ' a str ) -> Self {
117
+ On { output, prefix }
118
+ }
119
+
120
+ /// Adds a message to the logs, if they are enabled.
121
+ /// This is a convenience method for adding a single message.
122
+ ///
123
+ /// Takes a closure that returns the message to add to avoid unnecessary allocations.
124
+ pub fn add ( & self , msg_fn : impl FnOnce ( ) -> String ) {
125
+ if let On { prefix, output } = & self {
126
+ let msg = msg_fn ( ) ;
127
+ match output {
128
+ LogOutput :: StdOut => println ! ( "{prefix}{msg}" ) ,
129
+ LogOutput :: StdErr => eprintln ! ( "{prefix}{msg}" ) ,
130
+ }
131
+ }
132
+ }
133
+ }
134
+
135
+ use Logger :: * ;
136
+
100
137
/// Checks if the data is valid wasm and compatibility with the CosmWasm API (imports and exports)
101
138
pub fn check_wasm ( wasm_code : & [ u8 ] , available_capabilities : & HashSet < String > ) -> VmResult < ( ) > {
139
+ check_wasm_with_logs ( wasm_code, available_capabilities, Off )
140
+ }
141
+
142
+ pub fn check_wasm_with_logs (
143
+ wasm_code : & [ u8 ] ,
144
+ available_capabilities : & HashSet < String > ,
145
+ logs : Logger < ' _ > ,
146
+ ) -> VmResult < ( ) > {
147
+ logs. add ( || format ! ( "Size of Wasm blob: {}" , wasm_code. len( ) ) ) ;
148
+
102
149
let mut module = ParsedWasm :: parse ( wasm_code) ?;
103
150
104
151
check_wasm_tables ( & module) ?;
105
152
check_wasm_memories ( & module) ?;
106
153
check_interface_version ( & module) ?;
107
- check_wasm_exports ( & module) ?;
108
- check_wasm_imports ( & module, SUPPORTED_IMPORTS ) ?;
109
- check_wasm_capabilities ( & module, available_capabilities) ?;
110
- check_wasm_functions ( & module) ?;
154
+ check_wasm_exports ( & module, logs ) ?;
155
+ check_wasm_imports ( & module, SUPPORTED_IMPORTS , logs ) ?;
156
+ check_wasm_capabilities ( & module, available_capabilities, logs ) ?;
157
+ check_wasm_functions ( & module, logs ) ?;
111
158
112
159
module. validate_funcs ( )
113
160
}
@@ -188,8 +235,11 @@ fn check_interface_version(module: &ParsedWasm) -> VmResult<()> {
188
235
}
189
236
}
190
237
191
- fn check_wasm_exports ( module : & ParsedWasm ) -> VmResult < ( ) > {
238
+ fn check_wasm_exports ( module : & ParsedWasm , logs : Logger ) -> VmResult < ( ) > {
192
239
let available_exports: HashSet < String > = module. exported_function_names ( None ) ;
240
+
241
+ logs. add ( || format ! ( "Exports: {}" , available_exports. to_string_limited( 20_000 ) ) ) ;
242
+
193
243
for required_export in REQUIRED_EXPORTS {
194
244
if !available_exports. contains ( * required_export) {
195
245
return Err ( VmError :: static_validation_err ( format ! (
@@ -203,7 +253,24 @@ fn check_wasm_exports(module: &ParsedWasm) -> VmResult<()> {
203
253
/// Checks if the import requirements of the contract are satisfied.
204
254
/// When this is not the case, we either have an incompatibility between contract and VM
205
255
/// or a error in the contract.
206
- fn check_wasm_imports ( module : & ParsedWasm , supported_imports : & [ & str ] ) -> VmResult < ( ) > {
256
+ fn check_wasm_imports (
257
+ module : & ParsedWasm ,
258
+ supported_imports : & [ & str ] ,
259
+ logs : Logger ,
260
+ ) -> VmResult < ( ) > {
261
+ logs. add ( || {
262
+ format ! (
263
+ "Imports ({}): {}" ,
264
+ module. imports. len( ) ,
265
+ module
266
+ . imports
267
+ . iter( )
268
+ . map( |import| full_import_name( import) )
269
+ . collect:: <Vec <_>>( )
270
+ . join( ", " )
271
+ )
272
+ } ) ;
273
+
207
274
if module. imports . len ( ) > MAX_IMPORTS {
208
275
return Err ( VmError :: static_validation_err ( format ! (
209
276
"Import count exceeds limit. Imports: {}. Limit: {}." ,
@@ -240,8 +307,15 @@ fn full_import_name(ie: &Import) -> String {
240
307
fn check_wasm_capabilities (
241
308
module : & ParsedWasm ,
242
309
available_capabilities : & HashSet < String > ,
310
+ logs : Logger ,
243
311
) -> VmResult < ( ) > {
244
312
let required_capabilities = required_capabilities_from_module ( module) ;
313
+ logs. add ( || {
314
+ format ! (
315
+ "Required capabilities: {}" ,
316
+ required_capabilities. to_string_limited( 20_000 )
317
+ )
318
+ } ) ;
245
319
if !required_capabilities. is_subset ( available_capabilities) {
246
320
// We switch to BTreeSet to get a sorted error message
247
321
let unavailable: BTreeSet < _ > = required_capabilities
@@ -255,7 +329,17 @@ fn check_wasm_capabilities(
255
329
Ok ( ( ) )
256
330
}
257
331
258
- fn check_wasm_functions ( module : & ParsedWasm ) -> VmResult < ( ) > {
332
+ fn check_wasm_functions ( module : & ParsedWasm , logs : Logger ) -> VmResult < ( ) > {
333
+ logs. add ( || format ! ( "Function count: {}" , module. function_count) ) ;
334
+ logs. add ( || format ! ( "Max function parameters: {}" , module. max_func_params) ) ;
335
+ logs. add ( || format ! ( "Max function results: {}" , module. max_func_results) ) ;
336
+ logs. add ( || {
337
+ format ! (
338
+ "Total function parameter count: {}" ,
339
+ module. total_func_params
340
+ )
341
+ } ) ;
342
+
259
343
if module. function_count > MAX_FUNCTIONS {
260
344
return Err ( VmError :: static_validation_err ( format ! (
261
345
"Wasm contract contains more than {MAX_FUNCTIONS} functions"
@@ -599,7 +683,7 @@ mod tests {
599
683
)
600
684
. unwrap ( ) ;
601
685
let module = ParsedWasm :: parse ( & wasm) . unwrap ( ) ;
602
- check_wasm_exports ( & module) . unwrap ( ) ;
686
+ check_wasm_exports ( & module, Off ) . unwrap ( ) ;
603
687
604
688
// this is invalid, as it doesn't any required export
605
689
let wasm = wat:: parse_str (
@@ -611,7 +695,7 @@ mod tests {
611
695
)
612
696
. unwrap ( ) ;
613
697
let module = ParsedWasm :: parse ( & wasm) . unwrap ( ) ;
614
- match check_wasm_exports ( & module) {
698
+ match check_wasm_exports ( & module, Off ) {
615
699
Err ( VmError :: StaticValidationErr { msg, .. } ) => {
616
700
assert ! ( msg. starts_with( "Wasm contract doesn't have required export: \" allocate\" " ) ) ;
617
701
}
@@ -630,7 +714,7 @@ mod tests {
630
714
)
631
715
. unwrap ( ) ;
632
716
let module = ParsedWasm :: parse ( & wasm) . unwrap ( ) ;
633
- match check_wasm_exports ( & module) {
717
+ match check_wasm_exports ( & module, Off ) {
634
718
Err ( VmError :: StaticValidationErr { msg, .. } ) => {
635
719
assert ! (
636
720
msg. starts_with( "Wasm contract doesn't have required export: \" deallocate\" " )
@@ -660,7 +744,7 @@ mod tests {
660
744
)"# ,
661
745
)
662
746
. unwrap ( ) ;
663
- check_wasm_imports ( & ParsedWasm :: parse ( & wasm) . unwrap ( ) , SUPPORTED_IMPORTS ) . unwrap ( ) ;
747
+ check_wasm_imports ( & ParsedWasm :: parse ( & wasm) . unwrap ( ) , SUPPORTED_IMPORTS , Off ) . unwrap ( ) ;
664
748
}
665
749
666
750
#[ test]
@@ -771,8 +855,8 @@ mod tests {
771
855
)"# ,
772
856
)
773
857
. unwrap ( ) ;
774
- let err =
775
- check_wasm_imports ( & ParsedWasm :: parse ( & wasm ) . unwrap ( ) , SUPPORTED_IMPORTS ) . unwrap_err ( ) ;
858
+ let err = check_wasm_imports ( & ParsedWasm :: parse ( & wasm ) . unwrap ( ) , SUPPORTED_IMPORTS , Off )
859
+ . unwrap_err ( ) ;
776
860
match err {
777
861
VmError :: StaticValidationErr { msg, .. } => {
778
862
assert_eq ! ( msg, "Import count exceeds limit. Imports: 101. Limit: 100." ) ;
@@ -809,7 +893,7 @@ mod tests {
809
893
"env.debug" ,
810
894
"env.query_chain" ,
811
895
] ;
812
- let result = check_wasm_imports ( & ParsedWasm :: parse ( & wasm) . unwrap ( ) , supported_imports) ;
896
+ let result = check_wasm_imports ( & ParsedWasm :: parse ( & wasm) . unwrap ( ) , supported_imports, Off ) ;
813
897
match result. unwrap_err ( ) {
814
898
VmError :: StaticValidationErr { msg, .. } => {
815
899
println ! ( "{msg}" ) ;
@@ -825,7 +909,7 @@ mod tests {
825
909
#[ test]
826
910
fn check_wasm_imports_of_old_contract ( ) {
827
911
let module = & ParsedWasm :: parse ( CONTRACT_0_7 ) . unwrap ( ) ;
828
- let result = check_wasm_imports ( module, SUPPORTED_IMPORTS ) ;
912
+ let result = check_wasm_imports ( module, SUPPORTED_IMPORTS , Off ) ;
829
913
match result. unwrap_err ( ) {
830
914
VmError :: StaticValidationErr { msg, .. } => {
831
915
assert ! (
@@ -839,7 +923,7 @@ mod tests {
839
923
#[ test]
840
924
fn check_wasm_imports_wrong_type ( ) {
841
925
let wasm = wat:: parse_str ( r#"(module (import "env" "db_read" (memory 1 1)))"# ) . unwrap ( ) ;
842
- let result = check_wasm_imports ( & ParsedWasm :: parse ( & wasm) . unwrap ( ) , SUPPORTED_IMPORTS ) ;
926
+ let result = check_wasm_imports ( & ParsedWasm :: parse ( & wasm) . unwrap ( ) , SUPPORTED_IMPORTS , Off ) ;
843
927
match result. unwrap_err ( ) {
844
928
VmError :: StaticValidationErr { msg, .. } => {
845
929
assert ! (
@@ -874,7 +958,7 @@ mod tests {
874
958
]
875
959
. into_iter ( )
876
960
. collect ( ) ;
877
- check_wasm_capabilities ( & module, & available) . unwrap ( ) ;
961
+ check_wasm_capabilities ( & module, & available, Off ) . unwrap ( ) ;
878
962
}
879
963
880
964
#[ test]
@@ -902,7 +986,7 @@ mod tests {
902
986
]
903
987
. into_iter ( )
904
988
. collect ( ) ;
905
- match check_wasm_capabilities ( & module, & available) . unwrap_err ( ) {
989
+ match check_wasm_capabilities ( & module, & available, Off ) . unwrap_err ( ) {
906
990
VmError :: StaticValidationErr { msg, .. } => assert_eq ! (
907
991
msg,
908
992
"Wasm contract requires unavailable capabilities: {\" sun\" }"
@@ -918,7 +1002,7 @@ mod tests {
918
1002
]
919
1003
. into_iter ( )
920
1004
. collect ( ) ;
921
- match check_wasm_capabilities ( & module, & available) . unwrap_err ( ) {
1005
+ match check_wasm_capabilities ( & module, & available, Off ) . unwrap_err ( ) {
922
1006
VmError :: StaticValidationErr { msg, .. } => assert_eq ! (
923
1007
msg,
924
1008
"Wasm contract requires unavailable capabilities: {\" sun\" , \" water\" }"
@@ -928,7 +1012,7 @@ mod tests {
928
1012
929
1013
// Available set 3
930
1014
let available = [ "freedom" . to_string ( ) ] . into_iter ( ) . collect ( ) ;
931
- match check_wasm_capabilities ( & module, & available) . unwrap_err ( ) {
1015
+ match check_wasm_capabilities ( & module, & available, Off ) . unwrap_err ( ) {
932
1016
VmError :: StaticValidationErr { msg, .. } => assert_eq ! (
933
1017
msg,
934
1018
"Wasm contract requires unavailable capabilities: {\" nutrients\" , \" sun\" , \" water\" }"
@@ -938,7 +1022,7 @@ mod tests {
938
1022
939
1023
// Available set 4
940
1024
let available = [ ] . into_iter ( ) . collect ( ) ;
941
- match check_wasm_capabilities ( & module, & available) . unwrap_err ( ) {
1025
+ match check_wasm_capabilities ( & module, & available, Off ) . unwrap_err ( ) {
942
1026
VmError :: StaticValidationErr { msg, .. } => assert_eq ! (
943
1027
msg,
944
1028
"Wasm contract requires unavailable capabilities: {\" nutrients\" , \" sun\" , \" water\" }"
@@ -960,7 +1044,7 @@ mod tests {
960
1044
. unwrap ( ) ;
961
1045
let module = ParsedWasm :: parse ( & wasm) . unwrap ( ) ;
962
1046
963
- match check_wasm_functions ( & module) . unwrap_err ( ) {
1047
+ match check_wasm_functions ( & module, Off ) . unwrap_err ( ) {
964
1048
VmError :: StaticValidationErr { msg, .. } => assert_eq ! (
965
1049
msg,
966
1050
"Wasm contract contains function with more than 100 parameters"
@@ -979,7 +1063,7 @@ mod tests {
979
1063
) )
980
1064
. unwrap ( ) ;
981
1065
let module = ParsedWasm :: parse ( & wasm) . unwrap ( ) ;
982
- match check_wasm_functions ( & module) . unwrap_err ( ) {
1066
+ match check_wasm_functions ( & module, Off ) . unwrap_err ( ) {
983
1067
VmError :: StaticValidationErr { msg, .. } => assert_eq ! (
984
1068
msg,
985
1069
"Wasm contract contains function with more than 1 results"
@@ -998,7 +1082,7 @@ mod tests {
998
1082
) )
999
1083
. unwrap ( ) ;
1000
1084
let module = ParsedWasm :: parse ( & wasm) . unwrap ( ) ;
1001
- match check_wasm_functions ( & module) . unwrap_err ( ) {
1085
+ match check_wasm_functions ( & module, Off ) . unwrap_err ( ) {
1002
1086
VmError :: StaticValidationErr { msg, .. } => {
1003
1087
assert_eq ! ( msg, "Wasm contract contains more than 20000 functions" )
1004
1088
}
0 commit comments