Skip to content

Commit

Permalink
Merge NativeUpdateHistory with HardForks (#2941)
Browse files Browse the repository at this point in the history
* Merge NativeUpdateHistory  with HardForks

* Change throw message

* Ensure Genesis is not configured

* Improve comment

* Remove Genesis from HF and follow the Anna suggestions

* Revert HF value changes
  • Loading branch information
shargon authored Nov 5, 2023
1 parent efa8659 commit 3fc8895
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 50 deletions.
26 changes: 4 additions & 22 deletions src/Neo/ProtocolSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
// Redistribution and use in source and binary forms with or without
// modifications are permitted.

using Microsoft.Extensions.Configuration;
using Neo.Cryptography.ECC;
using Neo.Network.P2P.Payloads;
using Neo.SmartContract.Native;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Neo.Cryptography.ECC;
using Neo.Network.P2P.Payloads;

namespace Neo
{
Expand Down Expand Up @@ -85,10 +84,8 @@ public record ProtocolSettings
public uint MaxTraceableBlocks { get; init; }

/// <summary>
/// Contains the update history of all native contracts.
/// Sets the block height from which a hardfork is activated.
/// </summary>
public IReadOnlyDictionary<string, uint[]> NativeUpdateHistory { get; init; }

public ImmutableDictionary<Hardfork, uint> Hardforks { get; init; }

/// <summary>
Expand Down Expand Up @@ -149,18 +146,6 @@ public record ProtocolSettings
MemoryPoolMaxTransactions = 50_000,
MaxTraceableBlocks = 2_102_400,
InitialGasDistribution = 52_000_000_00000000,
NativeUpdateHistory = new Dictionary<string, uint[]>
{
[nameof(ContractManagement)] = new[] { 0u },
[nameof(StdLib)] = new[] { 0u },
[nameof(CryptoLib)] = new[] { 0u },
[nameof(LedgerContract)] = new[] { 0u },
[nameof(NeoToken)] = new[] { 0u },
[nameof(GasToken)] = new[] { 0u },
[nameof(PolicyContract)] = new[] { 0u },
[nameof(RoleManagement)] = new[] { 0u },
[nameof(OracleContract)] = new[] { 0u }
},
Hardforks = ImmutableDictionary<Hardfork, uint>.Empty
};

Expand Down Expand Up @@ -202,9 +187,6 @@ public static ProtocolSettings Load(IConfigurationSection section)
MemoryPoolMaxTransactions = section.GetValue("MemoryPoolMaxTransactions", Default.MemoryPoolMaxTransactions),
MaxTraceableBlocks = section.GetValue("MaxTraceableBlocks", Default.MaxTraceableBlocks),
InitialGasDistribution = section.GetValue("InitialGasDistribution", Default.InitialGasDistribution),
NativeUpdateHistory = section.GetSection("NativeUpdateHistory").Exists()
? section.GetSection("NativeUpdateHistory").GetChildren().ToDictionary(p => p.Key, p => p.GetChildren().Select(q => uint.Parse(q.Value)).ToArray())
: Default.NativeUpdateHistory,
Hardforks = section.GetSection("Hardforks").Exists()
? section.GetSection("Hardforks").GetChildren().ToImmutableDictionary(p => Enum.Parse<Hardfork>(p.Key), p => uint.Parse(p.Value))
: Default.Hardforks
Expand Down
13 changes: 3 additions & 10 deletions src/Neo/SmartContract/ApplicationEngine.Contract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,7 @@ protected internal void CallNativeContract(byte version)
NativeContract contract = NativeContract.GetContract(CurrentScriptHash);
if (contract is null)
throw new InvalidOperationException("It is not allowed to use \"System.Contract.CallNative\" directly.");
uint[] updates = ProtocolSettings.NativeUpdateHistory[contract.Name];
if (updates.Length == 0)
throw new InvalidOperationException($"The native contract {contract.Name} is not active.");
if (updates[0] > NativeContract.Ledger.CurrentIndex(Snapshot))
if (!contract.IsActive(ProtocolSettings, NativeContract.Ledger.CurrentIndex(Snapshot)))
throw new InvalidOperationException($"The native contract {contract.Name} is not active.");
contract.Invoke(this, version);
}
Expand Down Expand Up @@ -157,9 +154,7 @@ protected internal async void NativeOnPersist()
throw new InvalidOperationException();
foreach (NativeContract contract in NativeContract.Contracts)
{
uint[] updates = ProtocolSettings.NativeUpdateHistory[contract.Name];
if (updates.Length == 0) continue;
if (updates[0] <= PersistingBlock.Index)
if (contract.IsActive(ProtocolSettings, PersistingBlock.Index))
await contract.OnPersist(this);
}
}
Expand All @@ -181,9 +176,7 @@ protected internal async void NativePostPersist()
throw new InvalidOperationException();
foreach (NativeContract contract in NativeContract.Contracts)
{
uint[] updates = ProtocolSettings.NativeUpdateHistory[contract.Name];
if (updates.Length == 0) continue;
if (updates[0] <= PersistingBlock.Index)
if (contract.IsActive(ProtocolSettings, PersistingBlock.Index))
await contract.PostPersist(this);
}
}
Expand Down
22 changes: 11 additions & 11 deletions src/Neo/SmartContract/Native/ContractManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,18 +106,18 @@ internal override async ContractTask OnPersist(ApplicationEngine engine)
{
foreach (NativeContract contract in Contracts)
{
uint[] updates = engine.ProtocolSettings.NativeUpdateHistory[contract.Name];
if (updates.Length == 0 || updates[0] != engine.PersistingBlock.Index)
continue;
engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(new ContractState
if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index))
{
Id = contract.Id,
Nef = contract.Nef,
Hash = contract.Hash,
Manifest = contract.Manifest
}));
engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray()));
await contract.Initialize(engine);
engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(new ContractState
{
Id = contract.Id,
Nef = contract.Nef,
Hash = contract.Hash,
Manifest = contract.Manifest
}));
engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray()));
await contract.Initialize(engine);
}
}
}

Expand Down
41 changes: 41 additions & 0 deletions src/Neo/SmartContract/Native/NativeContract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ public abstract class NativeContract
/// </summary>
public string Name => GetType().Name;

/// <summary>
/// Since Hardfork has to start having access to the native contract.
/// </summary>
public virtual Hardfork? ActiveIn { get; } = null;

/// <summary>
/// The nef of the native contract.
/// </summary>
Expand Down Expand Up @@ -160,6 +165,42 @@ protected NativeContract()
contractsDictionary.Add(Hash, this);
}

/// <summary>
/// It is the initialize block
/// </summary>
/// <param name="settings">The <see cref="ProtocolSettings"/> where the HardForks are configured.</param>
/// <param name="index">Block index</param>
/// <returns>True if the native contract must be initialized</returns>
internal bool IsInitializeBlock(ProtocolSettings settings, uint index)
{
if (ActiveIn is null) return index == 0;

if (!settings.Hardforks.TryGetValue(ActiveIn.Value, out var activeIn))
{
return false;
}

return activeIn == index;
}

/// <summary>
/// Is the native contract active
/// </summary>
/// <param name="settings">The <see cref="ProtocolSettings"/> where the HardForks are configured.</param>
/// <param name="index">Block index</param>
/// <returns>True if the native contract is active</returns>
internal bool IsActive(ProtocolSettings settings, uint index)
{
if (ActiveIn is null) return true;

if (!settings.Hardforks.TryGetValue(ActiveIn.Value, out var activeIn))
{
return false;
}

return activeIn <= index;
}

/// <summary>
/// Checks whether the committee has witnessed the current transaction.
/// </summary>
Expand Down
7 changes: 0 additions & 7 deletions tests/Neo.UnitTests/UT_ProtocolSettings.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Neo.SmartContract.Native;
using Neo.Wallets;

namespace Neo.UnitTests
Expand Down Expand Up @@ -41,11 +40,5 @@ public void TestGetSeedList()
{
ProtocolSettings.Default.SeedList.Should().BeEquivalentTo(new string[] { "seed1.neo.org:10333", "seed2.neo.org:10333", "seed3.neo.org:10333", "seed4.neo.org:10333", "seed5.neo.org:10333", });
}

[TestMethod]
public void TestNativeUpdateHistory()
{
ProtocolSettings.Default.NativeUpdateHistory.Count.Should().Be(NativeContract.Contracts.Count);
}
}
}

0 comments on commit 3fc8895

Please sign in to comment.