diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs
index 5373db8bf0..f1e4e01b11 100644
--- a/src/Neo/ProtocolSettings.cs
+++ b/src/Neo/ProtocolSettings.cs
@@ -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
{
@@ -85,10 +84,8 @@ public record ProtocolSettings
public uint MaxTraceableBlocks { get; init; }
///
- /// Contains the update history of all native contracts.
+ /// Sets the block height from which a hardfork is activated.
///
- public IReadOnlyDictionary NativeUpdateHistory { get; init; }
-
public ImmutableDictionary Hardforks { get; init; }
///
@@ -149,18 +146,6 @@ public record ProtocolSettings
MemoryPoolMaxTransactions = 50_000,
MaxTraceableBlocks = 2_102_400,
InitialGasDistribution = 52_000_000_00000000,
- NativeUpdateHistory = new Dictionary
- {
- [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.Empty
};
@@ -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(p.Key), p => uint.Parse(p.Value))
: Default.Hardforks
diff --git a/src/Neo/SmartContract/ApplicationEngine.Contract.cs b/src/Neo/SmartContract/ApplicationEngine.Contract.cs
index f3d33e7d77..059c9eef07 100644
--- a/src/Neo/SmartContract/ApplicationEngine.Contract.cs
+++ b/src/Neo/SmartContract/ApplicationEngine.Contract.cs
@@ -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);
}
@@ -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);
}
}
@@ -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);
}
}
diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs
index f7ed44542d..62e9bb366d 100644
--- a/src/Neo/SmartContract/Native/ContractManagement.cs
+++ b/src/Neo/SmartContract/Native/ContractManagement.cs
@@ -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);
+ }
}
}
diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs
index 63c15466fb..8c8ffe986f 100644
--- a/src/Neo/SmartContract/Native/NativeContract.cs
+++ b/src/Neo/SmartContract/Native/NativeContract.cs
@@ -87,6 +87,11 @@ public abstract class NativeContract
///
public string Name => GetType().Name;
+ ///
+ /// Since Hardfork has to start having access to the native contract.
+ ///
+ public virtual Hardfork? ActiveIn { get; } = null;
+
///
/// The nef of the native contract.
///
@@ -160,6 +165,42 @@ protected NativeContract()
contractsDictionary.Add(Hash, this);
}
+ ///
+ /// It is the initialize block
+ ///
+ /// The where the HardForks are configured.
+ /// Block index
+ /// True if the native contract must be initialized
+ 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;
+ }
+
+ ///
+ /// Is the native contract active
+ ///
+ /// The where the HardForks are configured.
+ /// Block index
+ /// True if the native contract is active
+ 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;
+ }
+
///
/// Checks whether the committee has witnessed the current transaction.
///
diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs
index 0af209e10f..42be0e69cc 100644
--- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs
+++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs
@@ -1,6 +1,5 @@
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using Neo.SmartContract.Native;
using Neo.Wallets;
namespace Neo.UnitTests
@@ -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);
- }
}
}