Skip to content

Commit e47ef7a

Browse files
shargonajara87vncoelhoAnnaShalevaWi1l-B0t
authored
Exec Factor with decimals (#4278)
* rebase with master * fix * clean changes * fix conflcits * clean changes * clean changes * Revert remove UT * Clean changes * Remove node changes * remove node * Update src/Neo/SmartContract/ApplicationEngine.cs Co-authored-by: Anna Shaleva <[email protected]> --------- Co-authored-by: Alvaro <[email protected]> Co-authored-by: Vitor Nazário Coelho <[email protected]> Co-authored-by: Anna Shaleva <[email protected]> Co-authored-by: Will <[email protected]>
1 parent d3949f9 commit e47ef7a

19 files changed

+251
-61
lines changed

src/Neo/Network/P2P/Payloads/Transaction.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,11 +339,11 @@ public virtual VerifyResult VerifyStateDependent(ProtocolSettings settings, Data
339339
return VerifyResult.InvalidAttribute;
340340
attributesFee += attribute.CalculateNetworkFee(snapshot, this);
341341
}
342-
long netFeeDatoshi = NetworkFee - (Size * NativeContract.Policy.GetFeePerByte(snapshot)) - attributesFee;
342+
var netFeeDatoshi = NetworkFee - (Size * NativeContract.Policy.GetFeePerByte(snapshot)) - attributesFee;
343343
if (netFeeDatoshi < 0) return VerifyResult.InsufficientFunds;
344344

345345
if (netFeeDatoshi > MaxVerificationGas) netFeeDatoshi = MaxVerificationGas;
346-
uint execFeeFactor = NativeContract.Policy.GetExecFeeFactor(snapshot);
346+
var execFeeFactor = NativeContract.Policy.GetExecFeeFactor(settings, snapshot, height);
347347
for (int i = 0; i < hashes.Length; i++)
348348
{
349349
if (IsSignatureContract(Witnesses[i].VerificationScript.Span) && IsSingleSignatureInvocationScript(Witnesses[i].InvocationScript, out var _))

src/Neo/SmartContract/ApplicationEngine.Contract.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ internal protected UInt160 CreateStandardAccount(ECPoint pubKey)
124124
long fee = IsHardforkEnabled(Hardfork.HF_Aspidochelone)
125125
? CheckSigPrice
126126
: 1 << 8;
127-
AddFee(fee * ExecFeeFactor);
127+
AddFee(fee * _execFeeFactor);
128128
return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash();
129129
}
130130

@@ -141,7 +141,7 @@ internal protected UInt160 CreateMultisigAccount(int m, ECPoint[] pubKeys)
141141
long fee = IsHardforkEnabled(Hardfork.HF_Aspidochelone)
142142
? CheckSigPrice * pubKeys.Length
143143
: 1 << 8;
144-
AddFee(fee * ExecFeeFactor);
144+
AddFee(fee * _execFeeFactor);
145145
return Contract.CreateMultiSigRedeemScript(m, pubKeys).ToScriptHash();
146146
}
147147

src/Neo/SmartContract/ApplicationEngine.Crypto.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ protected internal bool CheckMultisig(byte[][] pubkeys, byte[][] signatures)
6969
if (n == 0) throw new ArgumentException("pubkeys array cannot be empty.");
7070
if (m == 0) throw new ArgumentException("signatures array cannot be empty.");
7171
if (m > n) throw new ArgumentException($"signatures count ({m}) cannot be greater than pubkeys count ({n}).");
72-
AddFee(CheckSigPrice * n * ExecFeeFactor);
72+
AddFee(CheckSigPrice * n * _execFeeFactor);
7373
try
7474
{
7575
for (int i = 0, j = 0; i < m && j < n;)

src/Neo/SmartContract/ApplicationEngine.Runtime.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ protected internal BigInteger GetRandom()
324324
buffer = nonceData = Cryptography.Helper.Murmur128(nonceData, ProtocolSettings.Network);
325325
price = 1 << 4;
326326
}
327-
AddFee(price * ExecFeeFactor);
327+
AddFee(price * _execFeeFactor);
328328
return new BigInteger(buffer, isUnsigned: true);
329329
}
330330

@@ -449,7 +449,7 @@ protected internal void BurnGas(long datoshi)
449449
{
450450
if (datoshi <= 0)
451451
throw new InvalidOperationException("GAS must be positive.");
452-
AddFee(datoshi);
452+
AddFee(datoshi * FeeFactor);
453453
}
454454

455455
/// <summary>

src/Neo/SmartContract/ApplicationEngine.Storage.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ protected internal void Put(StorageContext context, byte[] key, byte[] value)
256256
else
257257
newDataSize = (item.Value.Length - 1) / 4 + 1 + value.Length - item.Value.Length;
258258
}
259-
AddFee(newDataSize * StoragePrice);
259+
AddFee(newDataSize * StoragePrice * FeeFactor);
260260

261261
item.Value = value;
262262
}

src/Neo/SmartContract/ApplicationEngine.cs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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)

src/Neo/SmartContract/Native/ContractManagement.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,10 +267,10 @@ private async ContractTask<ContractState> Deploy(ApplicationEngine engine, byte[
267267
if (manifest.Length == 0)
268268
throw new ArgumentException($"Manifest length cannot be zero.");
269269

270-
engine.AddFee(Math.Max(
271-
engine.StoragePrice * (nefFile.Length + manifest.Length),
272-
GetMinimumDeploymentFee(engine.SnapshotCache)
273-
));
270+
// In the unit of picoGAS, 1 picoGAS = 1e-12 GAS
271+
engine.AddFee(BigInteger.Max(engine.StoragePrice * (nefFile.Length + manifest.Length),
272+
GetMinimumDeploymentFee(engine.SnapshotCache))
273+
* ApplicationEngine.FeeFactor);
274274

275275
NefFile nef = nefFile.AsSerializable<NefFile>();
276276
ContractManifest parsedManifest = ContractManifest.Parse(manifest);
@@ -336,7 +336,7 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man
336336
if (nefFile is null && manifest is null)
337337
throw new ArgumentException("NEF file and manifest cannot both be null.");
338338

339-
engine.AddFee(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0)));
339+
engine.AddFee(engine.StoragePrice * ApplicationEngine.FeeFactor * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0)));
340340

341341
var contractState = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Contract, engine.CallingScriptHash!))
342342
?? throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}");

src/Neo/SmartContract/Native/NativeContract.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,10 @@ internal async void Invoke(ApplicationEngine engine, byte version)
432432
var state = context.GetState<ExecutionContextState>();
433433
if (!state.CallFlags.HasFlag(method.RequiredCallFlags))
434434
throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}.");
435-
// In the unit of datoshi, 1 datoshi = 1e-8 GAS
436-
engine.AddFee(method.CpuFee * engine.ExecFeeFactor + method.StorageFee * engine.StoragePrice);
435+
// In the unit of picoGAS, 1 picoGAS = 1e-12 GAS
436+
engine.AddFee(
437+
(method.CpuFee * engine.ExecFeePicoFactor) +
438+
(method.StorageFee * engine.StoragePrice * ApplicationEngine.FeeFactor));
437439
List<object?> parameters = new();
438440
if (method.NeedApplicationEngine) parameters.Add(engine);
439441
if (method.NeedSnapshot) parameters.Add(engine.SnapshotCache);

src/Neo/SmartContract/Native/NeoToken.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,8 +406,8 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey)
406406
if (!engine.IsHardforkEnabled(Hardfork.HF_Echidna) &&
407407
!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash()))
408408
return false;
409-
// In the unit of datoshi, 1 datoshi = 1e-8 GAS
410-
engine.AddFee(GetRegisterPrice(engine.SnapshotCache));
409+
// In the unit of picoGAS, 1 picoGAS = 1e-12 GAS
410+
engine.AddFee(GetRegisterPrice(engine.SnapshotCache) * ApplicationEngine.FeeFactor);
411411
return RegisterInternal(engine, pubkey);
412412
}
413413

src/Neo/SmartContract/Native/OracleContract.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,10 +228,10 @@ private async ContractTask Request(ApplicationEngine engine, string url, string?
228228
if (gasForResponse < 0_10000000)
229229
throw new ArgumentException($"gasForResponse {gasForResponse} must be at least 0.1 datoshi.");
230230

231-
engine.AddFee(GetPrice(engine.SnapshotCache));
231+
engine.AddFee(GetPrice(engine.SnapshotCache) * ApplicationEngine.FeeFactor);
232232

233233
//Mint gas for the response
234-
engine.AddFee(gasForResponse);
234+
engine.AddFee(gasForResponse * ApplicationEngine.FeeFactor);
235235
await GAS.Mint(engine, Hash, gasForResponse, false);
236236

237237
//Increase the request id

0 commit comments

Comments
 (0)