Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
474c2f5
Start two decimal execution factor
shargon Oct 1, 2025
08e3a35
Revert "Start two decimal execution factor"
shargon Oct 2, 2025
3c58e8c
Draft with two dec
shargon Oct 2, 2025
d9c4b4c
Check HF in max values
shargon Oct 2, 2025
006bac1
Add comments
shargon Oct 2, 2025
ad5365e
4 decimals
shargon Oct 3, 2025
5b04634
Add extra checks
shargon Oct 3, 2025
0cafd92
Anna's feedback
shargon Oct 3, 2025
c19b679
Use CeilingDivide
shargon Oct 3, 2025
6bb4a7e
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 6, 2025
142e3e9
Merge branch 'dev' into exec-fee-two-decimals
ajara87 Oct 10, 2025
8e9fa33
Merge branch 'dev' into exec-fee-two-decimals
cschuchardt88 Oct 11, 2025
be10b0d
Apply suggestions from code review
shargon Oct 11, 2025
d9138d5
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 11, 2025
c372676
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 13, 2025
fdd894f
Merge branch 'dev' into exec-fee-two-decimals
cschuchardt88 Oct 13, 2025
373076e
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 13, 2025
f9ee97d
@cschuchardt88 review
shargon Oct 13, 2025
329b663
@ajara87 review
shargon Oct 13, 2025
f587b6e
Fix Pico gas
shargon Oct 13, 2025
86c2f3f
change to ulong
shargon Oct 13, 2025
699ad0b
Partial UT fix
shargon Oct 13, 2025
98a8975
Ensure settings is not null, use default
shargon Oct 13, 2025
827431d
clean gas left
shargon Oct 13, 2025
abbdd02
@shargon you forgot to add hardfork to `VerifyStateDependent`
cschuchardt88 Oct 13, 2025
bc0bfad
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 14, 2025
9654a83
Revert "@shargon you forgot to add hardfork to `VerifyStateDependent`"
shargon Oct 14, 2025
3e25cdc
settings != null
shargon Oct 14, 2025
f0db0db
Change to BigInteger and divide StoragePrice and ExecFactor by Factor
shargon Oct 14, 2025
93f0328
Add comments
shargon Oct 14, 2025
c1c163e
Partially errors fix
shargon Oct 14, 2025
1cb17b7
Fix SetFeePerByte
shargon Oct 14, 2025
e82fe09
Try to fix oracle ut
shargon Oct 14, 2025
e3d41b2
IsHardforkEnabledInNextBlock
shargon Oct 14, 2025
1152855
4 ut
shargon Oct 14, 2025
b8ccc56
Rpc fix
shargon Oct 14, 2025
5e78ca3
clean
shargon Oct 14, 2025
4b4e2c4
Add comments
shargon Oct 14, 2025
d3cb485
Avoid break compatibility
shargon Oct 15, 2025
f9db4e4
fix some uts
shargon Oct 15, 2025
25acde7
fix ut
shargon Oct 15, 2025
dec0a79
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 15, 2025
8ec994c
Use the right factor
shargon Oct 16, 2025
6b6d5c4
Fix gas
shargon Oct 16, 2025
edaae4c
Update src/Neo/SmartContract/Native/PolicyContract.cs
shargon Oct 16, 2025
e964a71
Update src/Neo/SmartContract/Native/PolicyContract.cs
shargon Oct 16, 2025
efc58fd
Merge branch 'dev' into exec-fee-two-decimals
cschuchardt88 Oct 17, 2025
83675ab
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 18, 2025
10ed040
update md
shargon Oct 18, 2025
3fbc3e8
Test half fee
shargon Oct 18, 2025
8e09fab
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 20, 2025
fbca971
Merge branch 'dev' into exec-fee-two-decimals
ajara87 Oct 23, 2025
c1dbd76
Merge branch 'dev' into exec-fee-two-decimals
cschuchardt88 Oct 23, 2025
01dbece
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 23, 2025
8538f2e
Apply suggestions from code review
shargon Oct 23, 2025
ef41ee3
Apply suggestions from code review
shargon Oct 23, 2025
63069f1
Merge branch 'dev' into exec-fee-two-decimals
ajara87 Oct 23, 2025
05f2598
Change only ExecFactor
shargon Oct 24, 2025
952c329
Clean changes
shargon Oct 24, 2025
204d637
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 24, 2025
0591dac
Merge branch 'dev' into exec-fee-two-decimals
Wi1l-B0t Oct 25, 2025
c1ebe81
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 25, 2025
252f7b6
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 28, 2025
20faa2f
Set GetExecPicoFeeFactor to Faun only
shargon Oct 29, 2025
9fa5998
Merge branch 'exec-fee-two-decimals' of https://github.com/neo-projec…
shargon Oct 29, 2025
86da21d
Update src/Neo/SmartContract/ApplicationEngine.cs
shargon Oct 29, 2025
24efa67
Merge branch 'dev' into exec-fee-two-decimals
shargon Oct 29, 2025
b3932fa
Update src/Neo/SmartContract/ApplicationEngine.cs
shargon Oct 29, 2025
391edb6
Merge branch 'dev' into exec-fee-two-decimals
shargon Nov 3, 2025
58d39a1
Update src/Neo/SmartContract/ApplicationEngine.cs
shargon Nov 5, 2025
e75721d
Fix changes
shargon Nov 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Neo/SmartContract/ApplicationEngine.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ protected internal void BurnGas(long datoshi)
{
if (datoshi <= 0)
throw new InvalidOperationException("GAS must be positive.");
AddFee(datoshi);
AddFee(datoshi * FeeFactor);
}

/// <summary>
Expand Down
43 changes: 27 additions & 16 deletions src/Neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,11 @@ public partial class ApplicationEngine : ExecutionEngine

private static Dictionary<uint, InteropDescriptor> services;
// Total amount of GAS spent to execute.
// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
private readonly long _feeAmount;
// In the unit of pico-datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
private readonly BigInteger _feeAmount;
private BigInteger _feeConsumed;
// Decimals for fee calculation
public const uint FeeFactor = 10000;
private Dictionary<Type, object> states;
private readonly DataCache originalSnapshotCache;
private List<NotifyEventArgs> notifications;
Expand Down Expand Up @@ -131,19 +134,19 @@ public partial class ApplicationEngine : ExecutionEngine
/// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
/// </summary>
[Obsolete("This property is deprecated. Use FeeConsumed instead.")]
public long GasConsumed { get; protected set; } = 0;
public long GasConsumed => FeeConsumed;

/// <summary>
/// GAS spent to execute.
/// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
/// </summary>
public long FeeConsumed { get; protected set; } = 0;
public long FeeConsumed => (long)_feeConsumed.CeilingDivide(FeeFactor);

/// <summary>
/// The remaining GAS that can be spent in order to complete the execution.
/// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi
/// </summary>
public long GasLeft => _feeAmount - FeeConsumed;
public long GasLeft => (long)(_feeAmount.CeilingDivide(FeeFactor) - FeeConsumed);

/// <summary>
/// The exception that caused the execution to terminate abnormally. This field could be <see langword="null"/> if no exception is thrown.
Expand Down Expand Up @@ -205,18 +208,28 @@ protected ApplicationEngine(
originalSnapshotCache = snapshotCache;
PersistingBlock = persistingBlock;
ProtocolSettings = settings;
_feeAmount = gas;
_feeAmount = gas * FeeFactor;
Diagnostic = diagnostic;
nonceData = container is Transaction tx ? tx.Hash.ToArray()[..16] : new byte[16];
if (snapshotCache is null || persistingBlock?.Index == 0)
{
ExecFeeFactor = PolicyContract.DefaultExecFeeFactor;
StoragePrice = PolicyContract.DefaultStoragePrice;
ExecFeeFactor = PolicyContract.DefaultExecFeeFactor * FeeFactor; // Add fee decimals
StoragePrice = PolicyContract.DefaultStoragePrice * FeeFactor;
}
else
{
ExecFeeFactor = NativeContract.Policy.GetExecFeeFactor(snapshotCache);
StoragePrice = NativeContract.Policy.GetStoragePrice(snapshotCache);
if (!settings.IsHardforkEnabled(Hardfork.HF_Faun, persistingBlock?.Index ?? 0))
{
// The values doesn't have the decimals stored
ExecFeeFactor = NativeContract.Policy.GetExecFeeFactor(snapshotCache) * FeeFactor;
StoragePrice = NativeContract.Policy.GetStoragePrice(snapshotCache) * FeeFactor;
}
else
{
// The values have the decimals stored
ExecFeeFactor = NativeContract.Policy.GetExecFeeFactor(snapshotCache);
StoragePrice = NativeContract.Policy.GetStoragePrice(snapshotCache);
}
}

if (persistingBlock is not null)
Expand Down Expand Up @@ -296,13 +309,11 @@ protected static void OnSysCall(ExecutionEngine engine, Instruction instruction)
/// <summary>
/// Adds GAS to <see cref="FeeConsumed"/> and checks if it has exceeded the maximum limit.
/// </summary>
/// <param name="datoshi">The amount of GAS, in the unit of datoshi, 1 datoshi = 1e-8 GAS, to be added.</param>
protected internal void AddFee(long datoshi)
/// <param name="picoDatoshi">The amount of GAS, in the unit of pico-datoshi, 1 datoshi = 1e-8 GAS, to be added.</param>
protected internal void AddFee(long picoDatoshi)
{
#pragma warning disable CS0618 // Type or member is obsolete
FeeConsumed = GasConsumed = checked(FeeConsumed + datoshi);
#pragma warning restore CS0618 // Type or member is obsolete
if (FeeConsumed > _feeAmount)
_feeConsumed = checked(_feeConsumed + picoDatoshi);
if (_feeConsumed > _feeAmount)
throw new InvalidOperationException("Insufficient GAS.");
}

Expand Down
2 changes: 1 addition & 1 deletion src/Neo/SmartContract/Native/NeoToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey)
!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash()))
return false;
// In the unit of datoshi, 1 datoshi = 1e-8 GAS
engine.AddFee(GetRegisterPrice(engine.SnapshotCache));
engine.AddFee(GetRegisterPrice(engine.SnapshotCache) * ApplicationEngine.FeeFactor);
return RegisterInternal(engine, pubkey);
}

Expand Down
4 changes: 2 additions & 2 deletions src/Neo/SmartContract/Native/OracleContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,10 @@ private async ContractTask Request(ApplicationEngine engine, string url, string
if (gasForResponse < 0_10000000)
throw new ArgumentException($"gasForResponse {gasForResponse} must be at least 0.1 datoshi.");

engine.AddFee(GetPrice(engine.SnapshotCache));
engine.AddFee(GetPrice(engine.SnapshotCache) * ApplicationEngine.FeeFactor);

//Mint gas for the response
engine.AddFee(gasForResponse);
engine.AddFee(gasForResponse * ApplicationEngine.FeeFactor);
await GAS.Mint(engine, Hash, gasForResponse, false);

//Increase the request id
Expand Down
26 changes: 22 additions & 4 deletions src/Neo/SmartContract/Native/PolicyContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,18 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor
engine.SnapshotCache.Add(_maxValidUntilBlockIncrement, new StorageItem(engine.ProtocolSettings.MaxValidUntilBlockIncrement));
engine.SnapshotCache.Add(_maxTraceableBlocks, new StorageItem(engine.ProtocolSettings.MaxTraceableBlocks));
}
if (hardfork == Hardfork.HF_Faun)
{
// Add decimals to exec fee factor
var item = engine.SnapshotCache.TryGet(_execFeeFactor) ??
throw new InvalidOperationException("Policy was not initialized");
item.Set((uint)(BigInteger)item * ApplicationEngine.FeeFactor);

// Add decimals to storage price
item = engine.SnapshotCache.TryGet(_storagePrice) ??
throw new InvalidOperationException("Policy was not initialized");
item.Set((uint)(BigInteger)item * ApplicationEngine.FeeFactor);
}
return ContractTask.CompletedTask;
}

Expand Down Expand Up @@ -342,17 +354,23 @@ private void SetFeePerByte(ApplicationEngine engine, long value)
[ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)]
private void SetExecFeeFactor(ApplicationEngine engine, uint value)
{
if (value == 0 || value > MaxExecFeeFactor)
throw new ArgumentOutOfRangeException(nameof(value), $"ExecFeeFactor must be between [1, {MaxExecFeeFactor}], got {value}");
// After FAUN hardfork, the max exec fee factor is with decimals defined in ApplicationEngine.FeeFactor
var maxValue = engine.IsHardforkEnabled(Hardfork.HF_Faun) ? ApplicationEngine.FeeFactor * MaxExecFeeFactor : MaxExecFeeFactor;

if (value == 0 || value > maxValue)
throw new ArgumentOutOfRangeException(nameof(value), $"ExecFeeFactor must be between [1, {maxValue}], got {value}");
if (!CheckCommittee(engine)) throw new InvalidOperationException();
engine.SnapshotCache.GetAndChange(_execFeeFactor).Set(value);
}

[ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)]
private void SetStoragePrice(ApplicationEngine engine, uint value)
{
if (value == 0 || value > MaxStoragePrice)
throw new ArgumentOutOfRangeException(nameof(value), $"StoragePrice must be between [1, {MaxStoragePrice}], got {value}");
// After FAUN hardfork, the max exec fee factor is with decimals defined in ApplicationEngine.FeeFactor
var maxValue = engine.IsHardforkEnabled(Hardfork.HF_Faun) ? (ulong)ApplicationEngine.FeeFactor * MaxStoragePrice : MaxStoragePrice;

if (value == 0 || value > maxValue)
throw new ArgumentOutOfRangeException(nameof(value), $"StoragePrice must be between [1, {maxValue}], got {value}");
if (!CheckCommittee(engine)) throw new InvalidOperationException();
engine.SnapshotCache.GetAndChange(_storagePrice).Set(value);
}
Expand Down
1 change: 1 addition & 0 deletions tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public void CeilingDivide_NegativeNumerator()
var result = BigIntegerExtensions.CeilingDivide(numerator, denominator);
Assert.AreEqual(-2, result);
}

[TestMethod]
public void CeilingDivide_DividesExactly()
{
Expand Down
Loading