contract_analyze/lib.rs
1// Copyright (C) Use Ink (UK) Ltd.
2// This file is part of cargo-contract.
3//
4// cargo-contract 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// cargo-contract 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 cargo-contract. If not, see <http://www.gnu.org/licenses/>.
16
17#![deny(unused_crate_dependencies)]
18
19use anyhow::{
20 bail,
21 Result,
22};
23pub use contract_metadata::Language;
24
25/// Detects the programming language of a smart contract from its PolkaVM
26/// binary code.
27///
28/// This function accepts a binary contract as input and employs a set of heuristics
29/// to identify the contract's source language. It currently supports detection of the
30/// ink! and Solidity languages.
31pub fn determine_language(_code: &[u8]) -> Result<Language> {
32 /*
33 // todo
34 if !start_section && module.custom_sections.keys().any(|e| e == &"producers") {
35 return Ok(Language::Solidity)
36 } else if start_section
37 && module
38 .custom_sections
39 .keys()
40 .any(|e| e == &"sourceMappingURL")
41 {
42 return Ok(Language::AssemblyScript)
43 } else if !start_section
44 && (is_ink_function_present(&module)
45 || matches!(module.has_function_name("ink_env"), Ok(true)))
46 {
47 return Ok(Language::Ink)
48 }
49 */
50
51 bail!("Language unsupported or unrecognized.")
52}
53
54#[cfg(test)]
55mod tests {
56 /*
57 // todo
58
59 #[test]
60 fn fails_with_unsupported_language() {
61 let contract = r#"
62 (module
63 (type $none_=>_none (func))
64 (type (;0;) (func (param i32 i32 i32)))
65 (import "env" "memory" (func (;5;) (type 0)))
66 (start $~start)
67 (func $~start (type $none_=>_none))
68 (func (;5;) (type 0))
69 )
70 "#;
71 let code = &wat::parse_str(contract).expect("Invalid wat.");
72 let lang = determine_language(code);
73 assert!(lang.is_err());
74 assert_eq!(
75 lang.unwrap_err().to_string(),
76 "Language unsupported or unrecognized."
77 );
78 }
79
80 #[test]
81 fn determines_ink_language() {
82 let contract = r#"
83 (module
84 (type (;0;) (func (param i32 i32 i32)))
85 (type (;1;) (func (result i32)))
86 (type (;2;) (func (param i32 i32)))
87 (import "seal" "foo" (func (;0;) (type 0)))
88 (import "seal0" "value_transferred" (func (;1;) (type 2)))
89 (import "env" "memory" (memory (;0;) 2 16))
90 (func (;2;) (type 2))
91 (func (;3;) (type 1) (result i32)
92 (local i32 i64 i64)
93 global.get 0
94 i32.const 32
95 i32.sub
96 local.tee 0
97 global.set 0
98 local.get 0
99 i64.const 0
100 i64.store offset=8
101 local.get 0
102 i64.const 0
103 i64.store
104 local.get 0
105 i32.const 16
106 i32.store offset=28
107 local.get 0
108 local.get 0
109 i32.const 28
110 i32.add
111 call 1
112 local.get 0
113 i64.load offset=8
114 local.set 1
115 local.get 0
116 i64.load
117 local.set 2
118 local.get 0
119 i32.const 32
120 i32.add
121 global.set 0
122 i32.const 5
123 i32.const 4
124 local.get 1
125 local.get 2
126 i64.or
127 i64.eqz
128 select
129 )
130 (global (;0;) (mut i32) (i32.const 65536))
131 )"#;
132 let code = &wat::parse_str(contract).expect("Invalid wat.");
133 let lang = determine_language(code);
134 assert!(
135 matches!(lang, Ok(Language::Ink)),
136 "Failed to detect Ink! language."
137 );
138 }
139
140 #[test]
141 fn determines_solidity_language() {
142 let contract = r#"
143 (module
144 (type (;0;) (func (param i32 i32 i32)))
145 (import "env" "memory" (memory (;0;) 16 16))
146 (func (;0;) (type 0))
147 (@custom "producers" "data")
148 )
149 "#;
150 let code = &wat::parse_str(contract).expect("Invalid wat.");
151 let lang = determine_language(code);
152 assert!(
153 matches!(lang, Ok(Language::Solidity)),
154 "Failed to detect Solidity language."
155 );
156 }
157
158 #[test]
159 fn determines_assembly_script_language() {
160 let contract = r#"
161 (module
162 (type $none_=>_none (func))
163 (type (;0;) (func (param i32 i32 i32)))
164 (import "seal" "foo" (func (;0;) (type 0)))
165 (import "env" "memory" (memory $0 2 16))
166 (start $~start)
167 (func $~start (type $none_=>_none))
168 (func (;1;) (type 0))
169 (@custom "sourceMappingURL" "data")
170 )
171 "#;
172 let code = &wat::parse_str(contract).expect("Invalid wat.");
173 let lang = determine_language(code);
174 assert!(
175 matches!(lang, Ok(Language::AssemblyScript)),
176 "Failed to detect AssemblyScript language."
177 );
178 }
179 */
180}