@@ -3,6 +3,7 @@ use crate::{
3
3
EmptyResult ,
4
4
ResultOf ,
5
5
} ;
6
+
6
7
use anyhow:: {
7
8
bail,
8
9
Context ,
@@ -30,7 +31,11 @@ use syn::{
30
31
Pat ,
31
32
Stmt ,
32
33
} ;
33
- use tempfile:: tempdir;
34
+ use toml_edit:: {
35
+ DocumentMut ,
36
+ Formatted ,
37
+ Value ,
38
+ } ;
34
39
35
40
#[ derive( Debug , Clone ) ]
36
41
pub struct SeedExtractInjector {
@@ -48,53 +53,85 @@ impl SeedExtractInjector {
48
53
compiled_path,
49
54
} )
50
55
}
56
+
57
+ /// Fork the contract, insert the snippet to extract the seeds, patch Cargo.toml, run the tests,
58
+ /// extracts the seeds.
51
59
pub fn prepare ( & self ) -> EmptyResult {
52
60
self . fork ( )
53
61
. context ( "Forking the project to a new directory failed" ) ?;
54
62
55
63
self . insert_snippet ( )
56
64
. context ( "Inserting the snippet into the file for seed extraction wasn't possible" ) ?;
57
65
58
- // self.build()
59
- // .context("Couldn't build the contract required for seed extraction")?;
66
+ self . patch_toml ( )
67
+ . context ( "Inserting the snippet into the file for seed extraction wasn't possible" ) ?;
68
+
69
+ self . build ( )
70
+ . context ( "Couldn't build the contract required for seed extraction" ) ?;
60
71
Ok ( ( ) )
61
72
}
62
73
63
74
pub fn run_tests ( & self ) -> EmptyResult {
64
75
todo ! ( )
65
76
}
66
77
78
+ /// Insert the snippet that will extract each call and send it via `debug_println!`
67
79
fn insert_snippet ( & self ) -> EmptyResult {
68
80
self . for_each_file ( |file_path| {
69
81
let source_code =
70
82
fs:: read_to_string ( & file_path) . context ( format ! ( "Couldn't read {file_path:?}" ) ) ?;
71
83
72
- self . instrument_file ( file_path, & source_code, self . clone ( ) )
84
+ self . instrument_file ( file_path, & source_code, self )
73
85
. context ( "Failed to instrument the file" )
74
86
} ) ?;
75
87
Ok ( ( ) )
76
88
}
77
- }
78
89
79
- impl ContractVisitor for SeedExtractInjector {
80
- fn input_directory ( & self ) -> PathBuf {
81
- self . contract_path . to_path_buf ( )
82
- }
90
+ /// Patch the `Cargo.toml` to use our own version of ink!
91
+ fn patch_toml ( & self ) -> EmptyResult {
92
+ let cargo_path = & self . output_directory ( ) . join ( "Cargo.toml" ) ;
93
+ let cargo_content = fs:: read_to_string ( cargo_path) ?;
94
+ let mut doc = cargo_content. parse :: < DocumentMut > ( ) ?;
95
+ const REPO : & str = "https://github.com/kevin-valerio/ink" ;
96
+
97
+ // Function to update ink dependencies in a table
98
+ fn update_ink_deps ( table : & mut toml_edit:: Table ) {
99
+ for ( key, value) in table. iter_mut ( ) {
100
+ if let toml_edit:: Item :: Value ( Value :: InlineTable ( dep_table) ) = value {
101
+ // Only modify if it's a table and contains a version
102
+ if dep_table. contains_key ( "version" ) {
103
+ // Check package name if specified, otherwise use the key
104
+ let dep_name = dep_table
105
+ . get ( "package" )
106
+ . and_then ( |v| v. as_str ( ) )
107
+ . unwrap_or ( & * key) ;
108
+
109
+ if dep_name. starts_with ( "ink_" ) || dep_name == "ink" {
110
+ dep_table. insert (
111
+ "git" ,
112
+ Value :: String ( Formatted :: new ( REPO . parse ( ) . unwrap ( ) ) ) ,
113
+ ) ;
114
+ }
115
+ }
116
+ }
117
+ }
118
+ }
83
119
84
- fn output_directory ( & self ) -> PathBuf {
85
- match & self . compiled_path {
86
- // We create a new directory in tmp/ if nothing is passed
87
- None => tempdir ( ) . unwrap ( ) . into_path ( ) ,
88
- Some ( contract) => contract. into ( ) ,
120
+ if let Some ( deps) = doc. get_mut ( "dependencies" ) . and_then ( |d| d. as_table_mut ( ) ) {
121
+ update_ink_deps ( deps) ;
89
122
}
90
- }
91
123
92
- fn verbose ( & self ) -> bool {
93
- true
124
+ if let Some ( dev_deps) = doc
125
+ . get_mut ( "dev-dependencies" )
126
+ . and_then ( |d| d. as_table_mut ( ) )
127
+ {
128
+ update_ink_deps ( dev_deps) ;
129
+ }
130
+
131
+ fs:: write ( cargo_path, doc. to_string ( ) ) ?;
132
+ Ok ( ( ) )
94
133
}
95
- }
96
134
97
- impl SeedExtractInjector {
98
135
/// Check if the function has the `#[ink(message)]` attribute
99
136
fn has_ink_message_attribute ( i : & mut ImplItemFn ) -> bool {
100
137
for attr in & i. attrs {
@@ -113,7 +150,33 @@ impl SeedExtractInjector {
113
150
}
114
151
}
115
152
116
- impl VisitMut for SeedExtractInjector {
153
+ impl ContractVisitor for SeedExtractInjector {
154
+ fn input_directory ( & self ) -> PathBuf {
155
+ self . contract_path . to_path_buf ( )
156
+ }
157
+
158
+ fn output_directory ( & self ) -> PathBuf {
159
+ let path = match & self . compiled_path {
160
+ None => {
161
+ // Create a new directory that is not tied to `TempDir`
162
+ let dir = std:: env:: temp_dir ( ) . join ( "phink_seedgen" ) ;
163
+ fs:: create_dir_all ( & dir) . expect ( "Failed to create directory" ) ;
164
+ dir
165
+ }
166
+ Some ( contract) => contract. to_path_buf ( ) ,
167
+ } ;
168
+ if self . verbose ( ) {
169
+ println ! ( "Using {path:?} for contract output" ) ;
170
+ }
171
+ path
172
+ }
173
+
174
+ fn verbose ( & self ) -> bool {
175
+ true
176
+ }
177
+ }
178
+
179
+ impl VisitMut for & SeedExtractInjector {
117
180
fn visit_item_mut ( & mut self , item : & mut Item ) {
118
181
match item {
119
182
Item :: Fn ( f) => self . visit_item_fn_mut ( f) ,
@@ -127,7 +190,7 @@ impl VisitMut for SeedExtractInjector {
127
190
fn visit_item_impl_mut ( & mut self , i : & mut ItemImpl ) {
128
191
for item in & mut i. items {
129
192
if let ImplItem :: Fn ( method) = item {
130
- if Self :: has_ink_message_attribute ( method) {
193
+ if SeedExtractInjector :: has_ink_message_attribute ( method) {
131
194
let fn_name = & method. sig . ident ;
132
195
// If the visited function isn't an invariant
133
196
if !fn_name. to_string ( ) . starts_with ( "phink_" ) {
@@ -195,7 +258,7 @@ impl VisitMut for SeedExtractInjector {
195
258
196
259
#[ cfg( test) ]
197
260
mod tests {
198
- use crate :: instrumenter:: seeder :: SeedExtractInjector ;
261
+ use crate :: instrumenter:: seedgen :: SeedExtractInjector ;
199
262
use quote:: quote;
200
263
use std:: path:: PathBuf ;
201
264
use syn:: {
@@ -243,7 +306,7 @@ mod tests {
243
306
if data.chars().nth(1).unwrap() == 'u' {
244
307
if data.chars().nth(2).unwrap() == 'z' {
245
308
if data.chars().nth(3).unwrap() == 'z' {
246
- self.forbidden_number = 69 ;
309
+ self.forbidden_number = 42 ;
247
310
}
248
311
}
249
312
}
@@ -282,15 +345,15 @@ mod tests {
282
345
#[cfg(feature = "phink")]
283
346
#[ink(message)]
284
347
pub fn phink_assert_dangerous_number(&self) {
285
- let forbidden_number = 69 ;
348
+ let forbidden_number = 42 ;
286
349
assert_ne!(self.forbidden_number, forbidden_number);
287
350
}
288
351
}
289
352
}"# ;
290
353
291
354
let mut syntax_tree: File = parse_str ( input_code) . expect ( "Failed to parse code" ) ;
292
355
let mut seed_injector =
293
- SeedExtractInjector :: new ( & PathBuf :: from ( "sample/dummy" ) , None ) . unwrap ( ) ;
356
+ & SeedExtractInjector :: new ( & PathBuf :: from ( "sample/dummy" ) , None ) . unwrap ( ) ;
294
357
seed_injector. visit_file_mut ( & mut syntax_tree) ;
295
358
296
359
let generated_code = quote ! ( #syntax_tree) . to_string ( ) ;
0 commit comments