@@ -248,6 +248,11 @@ pub struct Gas {
248248}
249249
250250impl Gas {
251+ /// Initialize a new gas value from its sub units.
252+ pub const fn new ( sub_units : u64 ) -> Self {
253+ Self { sub : sub_units }
254+ }
255+
251256 /// Checked add of `Gas`. Returns `None` on overflow
252257 pub fn checked_add ( & self , rhs : Self ) -> Option < Self > {
253258 self . sub . checked_add ( rhs. sub ) . map ( |sub| Self { sub } )
@@ -353,6 +358,29 @@ pub trait GasMetering {
353358 /// will still be updated
354359 fn consume ( & mut self , gas : Gas ) -> Result < ( ) > ;
355360
361+ /// Get the gas initially available to the gas meter
362+ ///
363+ /// This value will be equal to the gas limit minus some
364+ /// gas that may have been consumed before the current
365+ /// meter was initialized
366+ fn get_initially_available_gas ( & self ) -> Gas ;
367+
368+ /// Get the gas consumed thus far
369+ fn get_consumed_gas ( & self ) -> Gas ;
370+
371+ /// Get the gas limit
372+ fn get_gas_limit ( & self ) -> Gas ;
373+
374+ /// Get the protocol gas scale
375+ fn get_gas_scale ( & self ) -> u64 ;
376+
377+ /// Get the amount of gas still available to the transaction
378+ fn get_available_gas ( & self ) -> Gas {
379+ self . get_gas_limit ( )
380+ . checked_sub ( self . get_consumed_gas ( ) )
381+ . unwrap_or_default ( )
382+ }
383+
356384 /// Add the compiling cost proportionate to the code length
357385 fn add_compiling_gas ( & mut self , bytes_len : u64 ) -> Result < ( ) > {
358386 self . consume (
@@ -383,56 +411,64 @@ pub trait GasMetering {
383411 )
384412 }
385413
386- /// Get the gas consumed by the tx
387- fn get_tx_consumed_gas ( & self ) -> Gas ;
388-
389- /// Get the gas limit
390- fn get_gas_limit ( & self ) -> Gas ;
391-
392- /// Get the protocol gas scale
393- fn get_gas_scale ( & self ) -> u64 ;
414+ /// Check if the meter ran out of gas. Starts with the initial gas.
415+ fn check_limit ( & self , gas : Gas ) -> Result < ( ) > {
416+ self . get_initially_available_gas ( )
417+ . checked_sub ( gas)
418+ . ok_or_else ( || {
419+ Error :: TransactionGasExceededError (
420+ self . get_gas_limit ( )
421+ . get_whole_gas_units ( self . get_gas_scale ( ) ) ,
422+ )
423+ } )
424+ . and ( Ok ( ( ) ) )
425+ }
394426
395- /// Check if the vps went out of gas. Starts with the gas consumed by the
396- /// transaction.
397- fn check_vps_limit ( & self , vps_gas : Gas ) -> Result < ( ) > {
398- let total = self
399- . get_tx_consumed_gas ( )
400- . checked_add ( vps_gas)
401- . ok_or ( Error :: GasOverflow ) ?;
402- let gas_limit = self . get_gas_limit ( ) ;
403- if total > gas_limit {
404- return Err ( Error :: TransactionGasExceededError (
405- gas_limit. get_whole_gas_units ( self . get_gas_scale ( ) ) ,
406- ) ) ;
407- }
427+ /// Add the gas required by a wrapper transaction which is comprised of:
428+ /// - cost of validating the wrapper tx
429+ /// - space that the transaction requires in the block
430+ /// - cost of downloading (as part of the block) the transaction bytes over
431+ /// the network
432+ fn add_wrapper_gas ( & mut self , tx_bytes : & [ u8 ] ) -> Result < ( ) > {
433+ self . consume ( WRAPPER_TX_VALIDATION_GAS . into ( ) ) ?;
408434
409- Ok ( ( ) )
435+ let bytes_len = tx_bytes. len ( ) as u64 ;
436+ self . consume (
437+ bytes_len
438+ . checked_mul (
439+ STORAGE_OCCUPATION_GAS_PER_BYTE
440+ + NETWORK_TRANSMISSION_GAS_PER_BYTE ,
441+ )
442+ . ok_or ( Error :: GasOverflow ) ?
443+ . into ( ) ,
444+ )
410445 }
411446}
412447
413448/// Gas metering in a transaction
414- #[ derive( Debug ) ]
449+ #[ derive( Debug , Default ) ]
415450pub struct TxGasMeter {
416451 /// Track gas overflow
417452 gas_overflow : bool ,
418- // The protocol gas scale
453+ /// The protocol gas scale
419454 gas_scale : u64 ,
420455 /// The gas limit for a transaction
421- pub tx_gas_limit : Gas ,
456+ tx_gas_limit : Gas ,
457+ /// Gas consumption of the tx
422458 transaction_gas : Gas ,
423459}
424460
425461/// Gas metering in a validity predicate
426- #[ derive( Debug ) ]
462+ #[ derive( Debug , Default ) ]
427463pub struct VpGasMeter {
428464 /// Track gas overflow
429465 gas_overflow : bool ,
430- // The protocol gas scale
466+ /// The protocol gas scale
431467 gas_scale : u64 ,
432468 /// The transaction gas limit
433469 tx_gas_limit : Gas ,
434470 /// The gas consumed by the transaction before the Vp
435- initial_gas : Gas ,
471+ prev_meter_consumed_gas : Gas ,
436472 /// The current gas usage in the VP
437473 current_gas : Gas ,
438474}
@@ -460,8 +496,12 @@ impl GasMetering for TxGasMeter {
460496 Ok ( ( ) )
461497 }
462498
463- /// Get the entire gas used by the transaction up until this point
464- fn get_tx_consumed_gas ( & self ) -> Gas {
499+ #[ inline]
500+ fn get_initially_available_gas ( & self ) -> Gas {
501+ self . get_gas_limit ( )
502+ }
503+
504+ fn get_consumed_gas ( & self ) -> Gas {
465505 if !self . gas_overflow {
466506 self . transaction_gas . clone ( )
467507 } else {
@@ -490,53 +530,6 @@ impl TxGasMeter {
490530 transaction_gas : Gas :: default ( ) ,
491531 }
492532 }
493-
494- /// Add the gas required by a wrapper transaction which is comprised of:
495- /// - cost of validating the wrapper tx
496- /// - space that the transaction requires in the block
497- /// - cost of downloading (as part of the block) the transaction bytes over
498- /// the network
499- pub fn add_wrapper_gas ( & mut self , tx_bytes : & [ u8 ] ) -> Result < ( ) > {
500- self . consume ( WRAPPER_TX_VALIDATION_GAS . into ( ) ) ?;
501-
502- let bytes_len = tx_bytes. len ( ) as u64 ;
503- self . consume (
504- bytes_len
505- . checked_mul (
506- STORAGE_OCCUPATION_GAS_PER_BYTE
507- + NETWORK_TRANSMISSION_GAS_PER_BYTE ,
508- )
509- . ok_or ( Error :: GasOverflow ) ?
510- . into ( ) ,
511- )
512- }
513-
514- /// Get the amount of gas still available to the transaction
515- pub fn get_available_gas ( & self ) -> Gas {
516- self . tx_gas_limit
517- . checked_sub ( self . transaction_gas . clone ( ) )
518- . unwrap_or_default ( )
519- }
520-
521- /// Set the amount of gas still available to the transaction.
522- ///
523- /// WARNING: Utmost care must be taken when using this function! This must
524- /// never increase the amount available.
525- pub fn set_available_gas ( & mut self , gas : impl Into < Gas > ) {
526- let gas: Gas = gas. into ( ) ;
527- let used_gas = self
528- . tx_gas_limit
529- . checked_sub ( gas)
530- . unwrap_or_else ( || self . tx_gas_limit . clone ( ) ) ;
531- debug_assert ! (
532- used_gas > self . transaction_gas,
533- "Used gas must not decrease from {:?}, but trying to set it to \
534- {:?}",
535- self . transaction_gas,
536- used_gas
537- ) ;
538- self . transaction_gas = used_gas;
539- }
540533}
541534
542535impl GasMetering for VpGasMeter {
@@ -554,7 +547,7 @@ impl GasMetering for VpGasMeter {
554547 } ) ?;
555548
556549 let current_total = self
557- . initial_gas
550+ . prev_meter_consumed_gas
558551 . checked_add ( self . current_gas . clone ( ) )
559552 . ok_or ( Error :: GasOverflow ) ?;
560553
@@ -567,14 +560,16 @@ impl GasMetering for VpGasMeter {
567560 Ok ( ( ) )
568561 }
569562
570- /// Get the gas consumed by the tx alone before the vps were executed
571- fn get_tx_consumed_gas ( & self ) -> Gas {
572- if !self . gas_overflow {
573- self . initial_gas . clone ( )
574- } else {
575- hints:: cold ( ) ;
576- u64:: MAX . into ( )
577- }
563+ fn get_initially_available_gas ( & self ) -> Gas {
564+ self . tx_gas_limit
565+ . checked_sub ( self . prev_meter_consumed_gas . clone ( ) )
566+ . unwrap_or_default ( )
567+ }
568+
569+ fn get_consumed_gas ( & self ) -> Gas {
570+ self . prev_meter_consumed_gas
571+ . checked_add ( self . get_vp_consumed_gas ( ) )
572+ . unwrap_or_else ( || u64:: MAX . into ( ) )
578573 }
579574
580575 fn get_gas_limit ( & self ) -> Gas {
@@ -587,13 +582,18 @@ impl GasMetering for VpGasMeter {
587582}
588583
589584impl VpGasMeter {
590- /// Initialize a new VP gas meter from the `TxGasMeter`
585+ /// Initialize a new VP gas meter from the [ `TxGasMeter`]
591586 pub fn new_from_tx_meter ( tx_gas_meter : & TxGasMeter ) -> Self {
587+ Self :: new_from_meter ( tx_gas_meter)
588+ }
589+
590+ /// Initialize a new VP gas meter from the given generic gas meter
591+ pub fn new_from_meter ( gas_meter : & impl GasMetering ) -> Self {
592592 Self {
593593 gas_overflow : false ,
594- gas_scale : tx_gas_meter . gas_scale ,
595- tx_gas_limit : tx_gas_meter . tx_gas_limit . clone ( ) ,
596- initial_gas : tx_gas_meter . transaction_gas . clone ( ) ,
594+ gas_scale : gas_meter . get_gas_scale ( ) ,
595+ tx_gas_limit : gas_meter . get_gas_limit ( ) ,
596+ prev_meter_consumed_gas : gas_meter . get_consumed_gas ( ) ,
597597 current_gas : Gas :: default ( ) ,
598598 }
599599 }
@@ -602,15 +602,6 @@ impl VpGasMeter {
602602 pub fn get_vp_consumed_gas ( & self ) -> Gas {
603603 self . current_gas . clone ( )
604604 }
605-
606- /// Get the amount of gas still available to the VP
607- pub fn get_available_gas ( & self ) -> Gas {
608- self . tx_gas_limit
609- . checked_sub ( self . initial_gas . clone ( ) )
610- . unwrap_or_default ( )
611- . checked_sub ( self . current_gas . clone ( ) )
612- . unwrap_or_default ( )
613- }
614605}
615606
616607#[ cfg( test) ]
0 commit comments