-
Notifications
You must be signed in to change notification settings - Fork 431
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fully separate block forks from timtestamp ones (#6419)
- Loading branch information
Showing
5 changed files
with
120 additions
and
113 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 35 additions & 62 deletions
97
src/Nethermind/Nethermind.Specs.Test/CustomSpecProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,59 @@ | ||
// SPDX-FileCopyrightText: 2022 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
using System; | ||
using System.Linq; | ||
using Nethermind.Core; | ||
using Nethermind.Core.Collections; | ||
using Nethermind.Core.Specs; | ||
using Nethermind.Int256; | ||
using Nethermind.Specs.ChainSpecStyle; | ||
using Nethermind.Specs.Forks; | ||
|
||
namespace Nethermind.Specs.Test | ||
{ | ||
public class CustomSpecProvider : ISpecProvider | ||
{ | ||
private ForkActivation? _theMergeBlock = null; | ||
private readonly (ForkActivation Activation, IReleaseSpec Spec)[] _transitions; | ||
|
||
public ulong NetworkId { get; } | ||
public ulong ChainId { get; } | ||
namespace Nethermind.Specs.Test; | ||
|
||
public ForkActivation[] TransitionActivations { get; } | ||
|
||
public CustomSpecProvider(params (ForkActivation Activation, IReleaseSpec Spec)[] transitions) : this(TestBlockchainIds.NetworkId, TestBlockchainIds.ChainId, transitions) | ||
{ | ||
} | ||
|
||
public CustomSpecProvider(ulong networkId, ulong chainId, params (ForkActivation Activation, IReleaseSpec Spec)[] transitions) | ||
{ | ||
NetworkId = networkId; | ||
ChainId = chainId; | ||
public class CustomSpecProvider : SpecProviderBase, ISpecProvider | ||
{ | ||
private ForkActivation? _theMergeBlock = null; | ||
|
||
if (transitions.Length == 0) | ||
{ | ||
throw new ArgumentException($"There must be at least one release specified when instantiating {nameof(CustomSpecProvider)}", $"{nameof(transitions)}"); | ||
} | ||
public ulong NetworkId { get; } | ||
public ulong ChainId { get; } | ||
|
||
_transitions = transitions.OrderBy(r => r.Activation).ToArray(); | ||
TransitionActivations = _transitions.Select(t => t.Activation).ToArray(); | ||
public CustomSpecProvider(params (ForkActivation Activation, IReleaseSpec Spec)[] transitions) : this(TestBlockchainIds.NetworkId, TestBlockchainIds.ChainId, transitions) | ||
{ | ||
} | ||
|
||
if (transitions[0].Activation.BlockNumber != 0L) | ||
{ | ||
throw new ArgumentException($"First release specified when instantiating {nameof(CustomSpecProvider)} should be at genesis block (0)", $"{nameof(transitions)}"); | ||
} | ||
} | ||
public CustomSpecProvider(ulong networkId, ulong chainId, params (ForkActivation Activation, IReleaseSpec Spec)[] transitions) | ||
{ | ||
NetworkId = networkId; | ||
ChainId = chainId; | ||
|
||
public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalDifficulty = null) | ||
{ | ||
if (blockNumber is not null) | ||
_theMergeBlock = (ForkActivation)blockNumber; | ||
if (terminalTotalDifficulty is not null) | ||
TerminalTotalDifficulty = terminalTotalDifficulty; | ||
} | ||
(ForkActivation Activation, IReleaseSpec Spec)[] orderedTransitions = transitions.OrderBy(r => r.Activation).ToArray(); | ||
|
||
public ForkActivation? MergeBlockNumber => _theMergeBlock; | ||
LoadTransitions(orderedTransitions); | ||
|
||
public ulong TimestampFork { get; set; } = ISpecProvider.TimestampForkNever; | ||
public UInt256? TerminalTotalDifficulty { get; set; } | ||
TransitionActivations = orderedTransitions.Select(t => t.Activation).ToArray(); | ||
} | ||
|
||
#pragma warning disable CS8602 | ||
#pragma warning disable CS8603 | ||
public IReleaseSpec GenesisSpec => _transitions.Length == 0 ? null : _transitions[0].Spec; | ||
#pragma warning restore CS8603 | ||
#pragma warning restore CS8602 | ||
public void UpdateMergeTransitionInfo(long? blockNumber, UInt256? terminalTotalDifficulty = null) | ||
{ | ||
if (blockNumber is not null) | ||
_theMergeBlock = (ForkActivation)blockNumber; | ||
if (terminalTotalDifficulty is not null) | ||
TerminalTotalDifficulty = terminalTotalDifficulty; | ||
} | ||
|
||
public IReleaseSpec GetSpec(ForkActivation forkActivation) => | ||
_transitions.TryGetSearchedItem(forkActivation, | ||
CompareTransitionOnBlock, | ||
out (ForkActivation Activation, IReleaseSpec Spec) transition) | ||
? transition.Spec | ||
: GenesisSpec; | ||
public ForkActivation? MergeBlockNumber => _theMergeBlock; | ||
|
||
private static int CompareTransitionOnBlock(ForkActivation forkActivation, (ForkActivation Activation, IReleaseSpec Spec) transition) => | ||
forkActivation.CompareTo(transition.Activation); | ||
public ulong TimestampFork { get; set; } = ISpecProvider.TimestampForkNever; | ||
public UInt256? TerminalTotalDifficulty { get; set; } | ||
|
||
public long? DaoBlockNumber | ||
public long? DaoBlockNumber | ||
{ | ||
get | ||
{ | ||
get | ||
{ | ||
(ForkActivation forkActivation, IReleaseSpec daoRelease) = _transitions.SingleOrDefault(t => t.Spec == Dao.Instance); | ||
return daoRelease is not null ? forkActivation.BlockNumber : null; | ||
} | ||
(ForkActivation forkActivation, IReleaseSpec? daoRelease) = _blockTransitions.SingleOrDefault(t => t.Spec == Dao.Instance); | ||
return daoRelease is not null ? forkActivation.BlockNumber : null; | ||
} | ||
|
||
} | ||
|
||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
src/Nethermind/Nethermind.Specs/ChainSpecStyle/SpecProviderBase.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// SPDX-FileCopyrightText: 2023 Demerzel Solutions Limited | ||
// SPDX-License-Identifier: LGPL-3.0-only | ||
|
||
using Nethermind.Core.Collections; | ||
using Nethermind.Core.Specs; | ||
using Nethermind.Logging; | ||
using System; | ||
using System.Linq; | ||
|
||
namespace Nethermind.Specs.ChainSpecStyle; | ||
|
||
public abstract class SpecProviderBase | ||
{ | ||
protected (ForkActivation Activation, IReleaseSpec Spec)[] _blockTransitions; | ||
private (ForkActivation Activation, IReleaseSpec Spec)[] _timestampTransitions; | ||
private ForkActivation? _firstTimestampActivation; | ||
protected readonly ILogger _logger; | ||
|
||
public SpecProviderBase(ILogger logger = null) | ||
{ | ||
_logger = logger; | ||
} | ||
|
||
protected void LoadTransitions((ForkActivation Activation, IReleaseSpec Spec)[] transitions) | ||
{ | ||
if (transitions.Length == 0) | ||
{ | ||
throw new ArgumentException($"There must be at least one release specified when instantiating {GetType()}", $"{nameof(transitions)}"); | ||
} | ||
|
||
if (transitions.First().Activation.BlockNumber != 0L) | ||
{ | ||
throw new ArgumentException($"First release specified when instantiating {GetType()} should be at genesis block (0)", $"{nameof(transitions)}"); | ||
} | ||
|
||
_blockTransitions = transitions.TakeWhile(t => t.Activation.Timestamp is null).ToArray(); | ||
_timestampTransitions = transitions.SkipWhile(t => t.Activation.Timestamp is null).ToArray(); | ||
_firstTimestampActivation = _timestampTransitions.Length != 0 ? _timestampTransitions.First().Activation : null; | ||
GenesisSpec = transitions.First().Spec; | ||
} | ||
|
||
public ForkActivation[] TransitionActivations { get; protected set; } | ||
|
||
public IReleaseSpec GenesisSpec { get; private set; } | ||
|
||
public IReleaseSpec GetSpec(ForkActivation activation) | ||
{ | ||
static int CompareTransitionOnActivation(ForkActivation activation, (ForkActivation Activation, IReleaseSpec Spec) transition) => | ||
activation.CompareTo(transition.Activation); | ||
|
||
(ForkActivation Activation, IReleaseSpec Spec)[] consideredTransitions = _blockTransitions; | ||
|
||
if (_firstTimestampActivation is not null && activation.Timestamp is not null) | ||
{ | ||
if (_firstTimestampActivation.Value.Timestamp < activation.Timestamp | ||
&& _firstTimestampActivation.Value.BlockNumber > activation.BlockNumber) | ||
{ | ||
if (_logger is not null && _logger.IsWarn) _logger.Warn($"Chainspec file is misconfigured! Timestamp transition is configured to happen before the last block transition."); | ||
} | ||
|
||
if (_firstTimestampActivation.Value.Timestamp <= activation.Timestamp) | ||
consideredTransitions = _timestampTransitions; | ||
} | ||
|
||
return consideredTransitions.TryGetSearchedItem(activation, | ||
CompareTransitionOnActivation, | ||
out (ForkActivation Activation, IReleaseSpec Spec) transition) | ||
? transition.Spec | ||
: GenesisSpec; | ||
} | ||
} |