@@ -36,6 +36,7 @@ struct BlockEntry {
3636 start_pos : usize ,
3737 /// Sum of costs of all instructions until end of the block.
3838 cost : u32 ,
39+ flow_up : bool ,
3940}
4041
4142struct Counter {
@@ -55,11 +56,13 @@ impl Counter {
5556 }
5657
5758 /// Begin a new block.
58- fn begin ( & mut self , cursor : usize , cost : u32 ) {
59+ fn begin ( & mut self , cursor : usize , cost : u32 , flow_up : bool ) {
5960 let block_idx = self . blocks . len ( ) ;
61+ println ! ( "beginning new block at idx: {:?}" , block_idx) ;
6062 self . blocks . push ( BlockEntry {
6163 start_pos : cursor,
6264 cost : cost,
65+ flow_up : flow_up,
6366 } ) ;
6467 self . stack . push ( block_idx) ;
6568 }
@@ -72,7 +75,7 @@ impl Counter {
7275 println ! ( "stack size after finalizing: {:?}" , self . stack. len( ) ) ;
7376 Ok ( ( ) )
7477 }
75-
78+
7679 fn increment_control_flow ( & mut self , val : u32 ) -> Result < ( ) , ( ) > {
7780 /*
7881 ;; if the current block and parent block has 0 cost, then we're seeing a sequence of nested blocks
@@ -105,29 +108,20 @@ impl Counter {
105108 )))
106109 */
107110
108- let stack_top = self . stack . last_mut ( ) . ok_or_else ( || ( ) ) ?;
109- let top_block = self . blocks . get_mut ( * stack_top) . ok_or_else ( || ( ) ) ?;
111+ // find closest ancestor block (starting from top of stack and going down) with blocked flow and add 1
110112
111- if top_block. cost > 0 || * stack_top == 0 {
112- // if current block already has cost (i.e. previous instructions), or if there's no parent block,
113- // then increment gas in this block
114- println ! ( "current block already has instructions, or no parent block. incrementing and returning..." ) ;
115- top_block. cost = top_block. cost . checked_add ( val) . ok_or_else ( || ( ) ) ?;
116- Ok ( ( ) )
117- } else {
118- // find closest ancestor block (starting from top of stack and going down) with useGas call and add 1
119- for ( i, stack_i) in self . stack . iter ( ) . rev ( ) . enumerate ( ) {
120- println ! ( "stack at position {}: {:?}" , i, stack_i) ;
121- let block_i = self . blocks . get_mut ( * stack_i) . ok_or_else ( || ( ) ) ?;
122- println ! ( "block_i has cost: {:?}" , block_i. cost) ;
123- if * stack_i == 0 || block_i. cost > 0 {
124- println ! ( "found ancestor with cost > 0 or root block. incrementing and returning..." ) ;
125- block_i. cost = block_i. cost . checked_add ( val) . ok_or_else ( || ( ) ) ?;
126- break ;
127- }
113+ for ( i, stack_i) in self . stack . iter ( ) . rev ( ) . enumerate ( ) {
114+ println ! ( "stack at position {}: {:?}" , i, stack_i) ;
115+ let block_i = self . blocks . get_mut ( * stack_i) . ok_or_else ( || ( ) ) ?;
116+ println ! ( "block_{:?} has cost: {:?}" , * stack_i, block_i. cost) ;
117+ if !block_i. flow_up || * stack_i == 0 {
118+ block_i. cost = block_i. cost . checked_add ( val) . ok_or_else ( || ( ) ) ?;
119+ println ! ( "found ancestor with blocked flow or no parent. incrementing to new cost: {:?} and returning..." , block_i. cost) ;
120+ break ;
128121 }
129- Ok ( ( ) )
130122 }
123+ Ok ( ( ) )
124+
131125 }
132126
133127 /// Increment the cost of the current block by the specified value.
@@ -136,6 +130,7 @@ impl Counter {
136130 let top_block = self . blocks . get_mut ( * stack_top) . ok_or_else ( || ( ) ) ?;
137131
138132 top_block. cost = top_block. cost . checked_add ( val) . ok_or_else ( || ( ) ) ?;
133+ println ! ( "instruction for current block. incrementing, new cost: {:?}" , top_block. cost) ;
139134
140135 Ok ( ( ) )
141136 }
@@ -164,8 +159,10 @@ fn add_grow_counter(module: elements::Module, rules: &rules::Set, gas_func: u32)
164159 . with_instructions ( elements:: Instructions :: new ( vec ! [
165160 GetLocal ( 0 ) ,
166161 GetLocal ( 0 ) ,
167- I64Const ( rules. grow_cost( ) as i64 ) ,
168- I64Mul ,
162+ // I64Const(rules.grow_cost() as i64),
163+ // I64Mul,
164+ I32Const ( rules. grow_cost( ) as i32 ) ,
165+ I32Mul ,
169166 // todo: there should be strong guarantee that it does not return anything on stack?
170167 Call ( gas_func) ,
171168 GrowMemory ( 0 ) ,
@@ -188,7 +185,7 @@ pub fn inject_counter(
188185 let mut counter = Counter :: new ( ) ;
189186
190187 // Begin an implicit function (i.e. `func...end`) block.
191- counter. begin ( 0 , 0 ) ;
188+ counter. begin ( 0 , 0 , false ) ;
192189
193190 for cursor in 0 ..instructions. elements ( ) . len ( ) {
194191 let instruction = & instructions. elements ( ) [ cursor] ;
@@ -197,36 +194,71 @@ pub fn inject_counter(
197194 // Increment previous block with the cost of the current opcode.
198195 let instruction_cost = rules. process ( instruction) ?;
199196 //counter.increment(instruction_cost)?;
200- counter. increment_control_flow ( instruction_cost) ?;
201197
202198 // Begin new block. The cost of the following opcodes until `End` or `Else` will
203199 // be included into this block.
200+
201+ // add cost, which may flow up to ancestor block
202+ counter. increment_control_flow ( instruction_cost) ?;
203+
204+ counter. begin ( cursor + 1 , 0 , true ) ;
204205
205- // begin blocks with cost 0
206- counter. begin ( cursor + 1 , 0 ) ;
207206 } ,
208207 If ( _) => {
208+ println ! ( "on if instruction. finalizing current block and beginning new..." ) ;
209209 // Increment previous block with the cost of the current opcode.
210210 let instruction_cost = rules. process ( instruction) ?;
211211 //counter.increment(instruction_cost)?;
212212 counter. increment_control_flow ( instruction_cost) ?;
213-
214- // begin If with cost 1.
215- counter. begin ( cursor + 1 , 1 ) ;
213+
214+ // begin If with cost 1, to force new costs added to top of block
215+ counter. begin ( cursor + 1 , 0 , false ) ;
216216 } ,
217- Loop ( _) => {
217+ BrIf ( _) => {
218+ println ! ( "on br_if instruction. finalizing current block and beginning new..." ) ;
218219 // Increment previous block with the cost of the current opcode.
219220 let instruction_cost = rules. process ( instruction) ?;
220221 //counter.increment(instruction_cost)?;
221222 counter. increment_control_flow ( instruction_cost) ?;
222-
223- // begin loop with cost 1.
224- counter. begin ( cursor + 1 , 1 ) ;
223+
224+ // on a br_if, we finalize the previous block because those instructions will always be executed.
225+ // intructions after the if will be executed conditionally, so we start a new block so that gasUsed can be called after the if.
226+ counter. finalize ( ) ?;
227+
228+ // begin If with cost 1, to force new costs added to top of block
229+ counter. begin ( cursor + 1 , 0 , false ) ;
225230 } ,
231+ Loop ( _) => {
232+ let instruction_cost = rules. process ( instruction) ?;
233+ //counter.increment(instruction_cost)?;
234+ //counter.increment_control_flow(instruction_cost)?;
235+
236+ counter. begin ( cursor + 1 , 0 , false ) ;
237+ // charge for the loop after the loop instruction
238+ // need to do this because the loop could be executed many times (the br_if that jumps to the loop is a separate instruction and gas charge)
239+ counter. increment_control_flow ( instruction_cost) ?;
240+ } ,
241+ Br ( _) => {
242+ // anything after a break is dead code.
243+ // for now, we treat dead code blocks like any other (the metering will not be executed)
244+ // TODO: handle properly and don't inject metering inside dead code blocks
245+ let instruction_cost = rules. process ( instruction) ?;
246+ counter. increment_control_flow ( instruction_cost) ?;
247+ counter. finalize ( ) ?;
248+ counter. begin ( cursor + 1 , 0 , false ) ;
249+ } ,
250+ // br_table is always followed by end (in the ecmul wasm code, at least)
251+ // BrTable(_,_) => { },
252+ // return is always followed by end (in the ecmul wasm code, at least)
253+ // Return => { },
226254 End => {
227255 // Just finalize current block.
256+ //counter.increment_control_flow(instruction_cost)?;
257+ // wasabi doesn't count end as an instruction, so neither will we (no gas charge)
258+
259+
228260 counter. finalize ( ) ?;
229- counter. begin ( cursor + 1 , 0 ) ;
261+ counter. begin ( cursor + 1 , 0 , false ) ;
230262 } ,
231263 Else => {
232264 // `Else` opcode is being encountered. So the case we are looking at:
@@ -240,12 +272,17 @@ pub fn inject_counter(
240272 // Finalize the current block ('then' part of the if statement),
241273 // and begin another one for the 'else' part.
242274 counter. finalize ( ) ?;
243- counter. begin ( cursor + 1 , 1 ) ;
244- }
275+ counter. begin ( cursor + 1 , 1 , false ) ;
276+ } ,
277+ Unreachable => {
278+ // charge nothing, do nothing
279+ println ! ( "skipping unreachable..." ) ;
280+ } ,
245281 _ => {
246282 // An ordinal non control flow instruction. Just increment the cost of the current block.
247283 let instruction_cost = rules. process ( instruction) ?;
248- counter. increment ( instruction_cost) ?;
284+ //counter.increment(instruction_cost)?;
285+ counter. increment_control_flow ( instruction_cost) ?;
249286 }
250287 }
251288 }
@@ -256,7 +293,8 @@ pub fn inject_counter(
256293 if block. cost > 0 {
257294 let effective_pos = block. start_pos + cumulative_offset;
258295
259- instructions. elements_mut ( ) . insert ( effective_pos, I64Const ( block. cost as i64 ) ) ;
296+ //instructions.elements_mut().insert(effective_pos, I64Const(block.cost as i64));
297+ instructions. elements_mut ( ) . insert ( effective_pos, I32Const ( block. cost as i32 ) ) ;
260298 instructions. elements_mut ( ) . insert ( effective_pos+1 , Call ( gas_func) ) ;
261299
262300 // Take into account these two inserted instructions.
@@ -278,7 +316,7 @@ pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set)
278316 let mut mbuilder = builder:: from_module ( module) ;
279317 let import_sig = mbuilder. push_signature (
280318 builder:: signature ( )
281- . param ( ) . i64 ( )
319+ . param ( ) . i32 ( )
282320 . build_sig ( )
283321 ) ;
284322
@@ -306,6 +344,7 @@ pub fn inject_gas_counter(module: elements::Module, rules: &rules::Set)
306344 match section {
307345 & mut elements:: Section :: Code ( ref mut code_section) => {
308346 for ref mut func_body in code_section. bodies_mut ( ) {
347+ println ! ( "doing metering over new function..." ) ;
309348 update_call_index ( func_body. code_mut ( ) , gas_func) ;
310349 if let Err ( _) = inject_counter ( func_body. code_mut ( ) , rules, gas_func) {
311350 error = true ;
0 commit comments