Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
5 changes: 3 additions & 2 deletions src/Neo/Hardfork.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace Neo
{
public enum Hardfork : byte
{
HF_Aspidochelone,
HF_Basilisk
HF_Genesis = 0,
HF_Aspidochelone = 1,
HF_Basilisk = 2
}
}
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))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How to update contracts with this?

Copy link
Member Author

@shargon shargon Nov 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the next step, this pr is only for merge the logics,but I want to create the manifest according to the HardFork and create a property in ContractMethod for the HardFork activation

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is good. It will be a great improvement.

{
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
47 changes: 47 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>
/// Active in
/// </summary>
public virtual Hardfork ActiveIn { get; } = Hardfork.HF_Genesis;

/// <summary>
/// The nef of the native contract.
/// </summary>
Expand Down Expand Up @@ -160,6 +165,48 @@ 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 != Hardfork.HF_Genesis)
{
if (!settings.Hardforks.TryGetValue(ActiveIn, out var activeIn))
{
throw new InvalidOperationException($"The hardfork '{ActiveIn}' required for {Name} is not configured in ProtocolSettings.");
}

return activeIn == index;
}

return index == 0;
}

/// <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 != Hardfork.HF_Genesis)
{
if (!settings.Hardforks.TryGetValue(ActiveIn, out var activeIn))
{
throw new InvalidOperationException($"The hardfork '{ActiveIn}' required for {Name} is not configured in ProtocolSettings.");
}

return activeIn <= index;
}

return true;
}

/// <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);
}
}
}