@@ -66,15 +66,19 @@ public partial class ApplicationEngine : ExecutionEngine
6666
6767 private static Dictionary < uint , InteropDescriptor > ? services ;
6868 // Total amount of GAS spent to execute.
69- // In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
70- private readonly long _feeAmount ;
69+ // In the unit of picoGAS, 1 picoGAS = 1e-12 GAS
70+ private readonly BigInteger _feeAmount ;
71+ private BigInteger _feeConsumed ;
72+ // Decimals for fee calculation
73+ public const uint FeeFactor = 10000 ;
7174 private Dictionary < Type , object > ? states ;
7275 private readonly DataCache originalSnapshotCache ;
7376 private List < NotifyEventArgs > ? notifications ;
7477 private List < IDisposable > ? disposables ;
7578 private readonly Dictionary < UInt160 , int > invocationCounter = new ( ) ;
7679 private readonly Dictionary < ExecutionContext , ContractTaskAwaiter > contractTasks = new ( ) ;
77- internal readonly uint ExecFeeFactor ;
80+ // In the unit of picoGAS, 1 picoGAS = 1e-12 GAS
81+ private readonly BigInteger _execFeeFactor ;
7882 // In the unit of datoshi, 1 datoshi = 1e-8 GAS
7983 internal readonly uint StoragePrice ;
8084 private byte [ ] nonceData ;
@@ -132,19 +136,29 @@ public partial class ApplicationEngine : ExecutionEngine
132136 /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
133137 /// </summary>
134138 [ Obsolete ( "This property is deprecated. Use FeeConsumed instead." ) ]
135- public long GasConsumed { get ; protected set ; } = 0 ;
139+ public long GasConsumed => FeeConsumed ;
140+
141+ /// <summary>
142+ /// Exec Fee Factor. In the unit of datoshi, 1 datoshi = 1e-8 GAS
143+ /// </summary>
144+ internal long ExecFeeFactor => ( long ) _execFeeFactor . DivideCeiling ( FeeFactor ) ;
136145
137146 /// <summary>
138147 /// GAS spent to execute.
139148 /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
140149 /// </summary>
141- public long FeeConsumed { get ; protected set ; } = 0 ;
150+ public long FeeConsumed => ( long ) _feeConsumed . DivideCeiling ( FeeFactor ) ;
151+
152+ /// <summary>
153+ /// Exec Fee Factor. In the unit of picoGAS, 1 picoGAS = 1e-12 GAS
154+ /// </summary>
155+ internal BigInteger ExecFeePicoFactor => _execFeeFactor ;
142156
143157 /// <summary>
144158 /// The remaining GAS that can be spent in order to complete the execution.
145159 /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
146160 /// </summary>
147- public long GasLeft => _feeAmount - FeeConsumed ;
161+ public long GasLeft => ( long ) ( ( _feeAmount - _feeConsumed ) / FeeFactor ) ;
148162
149163 /// <summary>
150164 /// The exception that caused the execution to terminate abnormally. This field could be <see langword="null"/> if no exception is thrown.
@@ -206,17 +220,31 @@ protected ApplicationEngine(
206220 originalSnapshotCache = snapshotCache ;
207221 PersistingBlock = persistingBlock ;
208222 ProtocolSettings = settings ;
209- _feeAmount = gas ;
223+ _feeAmount = gas * FeeFactor ; // PicoGAS
210224 Diagnostic = diagnostic ;
211225 nonceData = container is Transaction tx ? tx . Hash . ToArray ( ) [ ..16 ] : new byte [ 16 ] ;
212226 if ( snapshotCache is null || persistingBlock ? . Index == 0 )
213227 {
214- ExecFeeFactor = PolicyContract . DefaultExecFeeFactor ;
228+ _execFeeFactor = PolicyContract . DefaultExecFeeFactor * FeeFactor ; // Add fee decimals
215229 StoragePrice = PolicyContract . DefaultStoragePrice ;
216230 }
217231 else
218232 {
219- ExecFeeFactor = NativeContract . Policy . GetExecFeeFactor ( snapshotCache ) ;
233+ var persistingIndex = persistingBlock ? . Index ?? NativeContract . Ledger . CurrentIndex ( snapshotCache ) ;
234+
235+ if ( settings == null || ! settings . IsHardforkEnabled ( Hardfork . HF_Faun , persistingIndex ) )
236+ {
237+ // The values doesn't have the decimals stored
238+ _execFeeFactor = NativeContract . Policy . GetExecFeeFactor ( this ) * FeeFactor ;
239+ }
240+ else
241+ {
242+ // The values have the decimals stored starting from OnPersist of Faun's block.
243+ _execFeeFactor = NativeContract . Policy . GetExecPicoFeeFactor ( this ) ;
244+ if ( trigger == TriggerType . OnPersist && persistingIndex > 0 && ! settings . IsHardforkEnabled ( Hardfork . HF_Faun , persistingIndex - 1 ) )
245+ _execFeeFactor *= FeeFactor ;
246+ }
247+
220248 StoragePrice = NativeContract . Policy . GetStoragePrice ( snapshotCache ) ;
221249 }
222250
@@ -297,13 +325,11 @@ protected static void OnSysCall(ExecutionEngine engine, Instruction instruction)
297325 /// <summary>
298326 /// Adds GAS to <see cref="FeeConsumed"/> and checks if it has exceeded the maximum limit.
299327 /// </summary>
300- /// <param name="datoshi ">The amount of GAS, in the unit of datoshi , 1 datoshi = 1e-8 GAS, to be added.</param>
301- protected internal void AddFee ( long datoshi )
328+ /// <param name="picoGas ">The amount of GAS, in the unit of picoGAS , 1 picoGAS = 1e-12 GAS, to be added.</param>
329+ protected internal void AddFee ( BigInteger picoGas )
302330 {
303- #pragma warning disable CS0618 // Type or member is obsolete
304- FeeConsumed = GasConsumed = checked ( FeeConsumed + datoshi ) ;
305- #pragma warning restore CS0618 // Type or member is obsolete
306- if ( FeeConsumed > _feeAmount )
331+ _feeConsumed = _feeConsumed + picoGas ;
332+ if ( _feeConsumed > _feeAmount )
307333 throw new InvalidOperationException ( "Insufficient GAS." ) ;
308334 }
309335
@@ -657,7 +683,7 @@ internal protected void ValidateCallFlags(CallFlags requiredCallFlags)
657683 protected virtual void OnSysCall ( InteropDescriptor descriptor )
658684 {
659685 ValidateCallFlags ( descriptor . RequiredCallFlags ) ;
660- AddFee ( descriptor . FixedPrice * ExecFeeFactor ) ;
686+ AddFee ( descriptor . FixedPrice * _execFeeFactor ) ;
661687
662688 object ? [ ] parameters = new object ? [ descriptor . Parameters . Count ] ;
663689 for ( int i = 0 ; i < parameters . Length ; i ++ )
@@ -671,7 +697,7 @@ protected virtual void OnSysCall(InteropDescriptor descriptor)
671697 protected override void PreExecuteInstruction ( Instruction instruction )
672698 {
673699 Diagnostic ? . PreExecuteInstruction ( instruction ) ;
674- AddFee ( ExecFeeFactor * OpCodePriceTable [ ( byte ) instruction . OpCode ] ) ;
700+ AddFee ( _execFeeFactor * OpCodePriceTable [ ( byte ) instruction . OpCode ] ) ;
675701 }
676702
677703 protected override void PostExecuteInstruction ( Instruction instruction )
0 commit comments