Skip to content

Commit

Permalink
Fix hardfork checking logic (#2886)
Browse files Browse the repository at this point in the history
* hardfork is disabled if not set in config

* update hardfork and revert change to ut

* update the hardfork logic

* check more edge cases

* optimize the hardfork checking.

* Format file

* cache allforks

* format

---------

Co-authored-by: Shargon <[email protected]>
  • Loading branch information
Jim8y and shargon authored Aug 29, 2023
1 parent 773b96a commit 24d1e7f
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 6 deletions.
32 changes: 31 additions & 1 deletion src/Neo/ProtocolSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ public static ProtocolSettings Load(string path, bool optional = true)
{
IConfigurationRoot config = new ConfigurationBuilder().AddJsonFile(path, optional).Build();
IConfigurationSection section = config.GetSection("ProtocolConfiguration");
return Load(section);
var settings = Load(section);
CheckingHardfork(settings);
return settings;
}

/// <summary>
Expand Down Expand Up @@ -208,5 +210,33 @@ public static ProtocolSettings Load(IConfigurationSection section)
: Default.Hardforks
};
}

private static void CheckingHardfork(ProtocolSettings settings)
{
var allHardforks = Enum.GetValues(typeof(Hardfork)).Cast<Hardfork>().ToList();
// Check for continuity in configured hardforks
var sortedHardforks = settings.Hardforks.Keys
.OrderBy(h => allHardforks.IndexOf(h))
.ToList();

for (int i = 0; i < sortedHardforks.Count - 1; i++)
{
int currentIndex = allHardforks.IndexOf(sortedHardforks[i]);
int nextIndex = allHardforks.IndexOf(sortedHardforks[i + 1]);

// If they aren't consecutive, return false.
if (nextIndex - currentIndex > 1)
throw new Exception("Hardfork configuration is not continuous.");
}
// Check that block numbers are not higher in earlier hardforks than in later ones
for (int i = 0; i < sortedHardforks.Count - 1; i++)
{
if (settings.Hardforks[sortedHardforks[i]] > settings.Hardforks[sortedHardforks[i + 1]])
{
// This means the block number for the current hardfork is greater than the next one, which should not be allowed.
throw new Exception($"The Hardfork configuration for {sortedHardforks[i]} is greater than for {sortedHardforks[i + 1]}");
}
}
}
}
}
26 changes: 22 additions & 4 deletions src/Neo/SmartContract/ApplicationEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public partial class ApplicationEngine : ExecutionEngine
/// </summary>
public static event EventHandler<LogEventArgs> Log;

private static readonly IList<Hardfork> AllHardforks = Enum.GetValues(typeof(Hardfork)).Cast<Hardfork>().ToArray();
private static Dictionary<uint, InteropDescriptor> services;
private readonly long gas_amount;
private Dictionary<Type, object> states;
Expand Down Expand Up @@ -612,11 +613,28 @@ public void SetState<T>(T state)

public bool IsHardforkEnabled(Hardfork hardfork)
{
if (PersistingBlock is null)
// Return true if there's no specific configuration or PersistingBlock is null
if (PersistingBlock is null || ProtocolSettings.Hardforks.Count == 0)
return true;
if (!ProtocolSettings.Hardforks.TryGetValue(hardfork, out uint height))
return true;
return PersistingBlock.Index >= height;

// If the hardfork isn't specified in the configuration, check if it's a new one.
if (!ProtocolSettings.Hardforks.ContainsKey(hardfork))
{
int currentHardforkIndex = AllHardforks.IndexOf(hardfork);
int lastConfiguredHardforkIndex = AllHardforks.IndexOf(ProtocolSettings.Hardforks.Keys.Last());

// If it's a newer hardfork compared to the ones in the configuration, disable it.
if (currentHardforkIndex > lastConfiguredHardforkIndex)
return false;
}

if (ProtocolSettings.Hardforks.TryGetValue(hardfork, out uint height))
{
// If the hardfork has a specific height in the configuration, check the block height.
return PersistingBlock.Index >= height;
}
// If no specific conditions are met, return true.
return true;
}
}
}
38 changes: 37 additions & 1 deletion tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.SmartContract;
using Neo.VM.Types;
using Array = Neo.VM.Types.Array;

namespace Neo.UnitTests.SmartContract
{
Expand Down Expand Up @@ -56,5 +59,38 @@ public void TestCreateDummyBlock()
engine.PersistingBlock.PrevHash.Should().Be(TestBlockchain.TheNeoSystem.GenesisBlock.Hash);
engine.PersistingBlock.MerkleRoot.Should().Be(new UInt256());
}

[TestMethod]
public void TestCheckingHardfork()
{
var allHardforks = Enum.GetValues(typeof(Hardfork)).Cast<Hardfork>().ToList();

var builder = ImmutableDictionary.CreateBuilder<Hardfork, uint>();
builder.Add(Hardfork.HF_Aspidochelone, 0);
builder.Add(Hardfork.HF_Basilisk, 1);

var setting = builder.ToImmutable();

// Check for continuity in configured hardforks
var sortedHardforks = setting.Keys
.OrderBy(h => allHardforks.IndexOf(h))
.ToList();

for (int i = 0; i < sortedHardforks.Count - 1; i++)
{
int currentIndex = allHardforks.IndexOf(sortedHardforks[i]);
int nextIndex = allHardforks.IndexOf(sortedHardforks[i + 1]);

// If they aren't consecutive, return false.
var inc = nextIndex - currentIndex;
inc.Should().Be(1);
}

// Check that block numbers are not higher in earlier hardforks than in later ones
for (int i = 0; i < sortedHardforks.Count - 1; i++)
{
(setting[sortedHardforks[i]] > setting[sortedHardforks[i + 1]]).Should().Be(false);
}
}
}
}

0 comments on commit 24d1e7f

Please sign in to comment.