Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]Make chainspec extendable by plugins #7540

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

deffrian
Copy link
Contributor

@deffrian deffrian commented Oct 2, 2024

Fixes Closes Resolves #
#6222
Right now our ChainSpec is a mess. This pr tries to fix some issues.

Changes

Adds new interface IChainSpecEngineParameters. This works similar to IConfig.

  1. In runtime we search for all inheritors of this interface and create instances. We set corresponding fields from chainspec file.
  2. During ReleaseSpec creation we call IChainSpecEngineParameters.AddTransitions. Plugin devs write implementation of this function if they want to add transitions.
  3. After all ReleaseSpec created we call IChainSpecEngineParameters.AdjustReleaseSpec. Plugin devs write implementation of this function if they want to change any parameters in ReleaseSpec.

Types of changes

What types of changes does your code introduce?

  • Bugfix (a non-breaking change that fixes an issue)
  • New feature (a non-breaking change that adds functionality)
  • Breaking change (a change that causes existing functionality not to work as expected)
  • Optimization
  • Refactoring
  • Documentation update
  • Build-related changes
  • Other: Description

Testing

Requires testing

  • Yes
  • No

If yes, did you write tests?

  • Yes
  • No

Notes on testing

Optional. Remove if not applicable.

Documentation

Requires documentation update

  • Yes
  • No

If yes, link the PR to the docs update or the issue with the details labeled docs. Remove if not applicable.

Requires explanation in Release Notes

  • Yes
  • No

If yes, fill in the details here. Remove if not applicable.

Remarks

Optional. Remove if not applicable.

@deffrian deffrian changed the title Make chainspec extendable by plugins [WIP]Make chainspec extendable by plugins Oct 2, 2024
Copy link
Member

@LukaszRozmej LukaszRozmej left a comment

Choose a reason for hiding this comment

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

I think the direction is good, but there is some details to iron out.

Comment on lines 39 to 44
// hex encoded byte array
string hex = valueString.Trim().RemoveStart('0').RemoveStart('x').TrimEnd();
value = Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
Copy link
Member

Choose a reason for hiding this comment

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

Bytes.FromHexString
AsSpan().Trim() if needed

src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs Outdated Show resolved Hide resolved
src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs Outdated Show resolved Hide resolved
value = null;
return false;
}
switch (Type.GetTypeCode(type))
Copy link
Member

Choose a reason for hiding this comment

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

Convert.ChangeType?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Dont understand what you mean

Comment on lines +11 to +12
private readonly long? _bedrockBlockNumber = parameters.BedrockBlockNumber;
private readonly ulong? _regolithTimestamp = parameters.RegolithTimestamp;
Copy link
Member

Choose a reason for hiding this comment

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

Why do we have to make stuff nullable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There might be no value in config, so better to make it nullable imo

JsonProperty? jsonProperty = _chainSpecParameters[engineName].EnumerateObject().FirstOrDefault(p =>
string.Compare(p.Name, property.Name, StringComparison.InvariantCultureIgnoreCase) == 0);

if (jsonProperty is null)
{
throw new FormatException($"ChainSpec property {property.Name} is not set");
}

object value = ConfigSourceHelper.ParseValue(property.PropertyType, jsonProperty.Value.Value.ToString(), "chainspec", property.Name);
property.SetValue(instance, value);
Copy link
Member

Choose a reason for hiding this comment

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

Can we just use json deserialization here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought best idea is to do th same way we do in config. Just extending capabilities for chainspec

private void InitializeInstances()
{
Type type = typeof(IChainSpecEngineParameters);
IEnumerable<Type> types = TypeDiscovery.FindNethermindBasedTypes(type).Where(x => x.IsClass);
Copy link
Member

Choose a reason for hiding this comment

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

Do we want auto-discovery or explicit registration?

Copy link
Contributor

Choose a reason for hiding this comment

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

In the Transaction type refactoring we've been working with explicit registration. This should make transitioning to a DI approach easier but makes the immediate code harder since you need to register at the appropriate time, a lot of times directly into static fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same argument, do as in config. But I don't mind both tbh

{
Type type = typeof(IChainSpecEngineParameters);
IEnumerable<Type> types = TypeDiscovery.FindNethermindBasedTypes(type).Where(x => x.IsClass);
foreach (Type @class in types)
Copy link
Member

Choose a reason for hiding this comment

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

Instances should be constructed lazily?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Construction is done on setup, so performance is not a concern(it takes small amount of time). I prefer to catch any miss-configuration errors at this point.

Copy link
Contributor

@emlautarom1 emlautarom1 left a comment

Choose a reason for hiding this comment

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

Some questions regarding nullability and discovery, but overall LGTM.

IEnumerable<Type> types = TypeDiscovery.FindNethermindBasedTypes(type).Where(x => x.IsClass);
foreach (Type @class in types)
{
string engineName = @class.Name.Remove(@class.Name.Length - EngineParamsSuffix.Length);
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we do the discovery based on implementing IChainSpecEngineParameters rather than class name? Even if we go with the manual registration route we could perform this check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure what you mean. It already looks for all inheritors of IChainSpecEngineParameters. I didn't make manual registration because ChainSpec is more similar to IConfig. So I thought we should behave the same way here

private readonly Dictionary<string, JsonElement> _chainSpecParameters =
new(StringComparer.InvariantCultureIgnoreCase);

private readonly ConcurrentDictionary<Type, IChainSpecEngineParameters> _instances = new();
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does this have to be concurrent? We cannot add elements through AllChainSpecParameters and there is no other accessor.

public interface IChainSpecParametersProvider
{
string SealEngineType { get; }
ICollection<IChainSpecEngineParameters> AllChainSpecParameters { get; }
Copy link
Contributor

Choose a reason for hiding this comment

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

If we don't intend to allow modification (which I think we don't) prefer IEnumerable to ICollection

{
ArgumentNullException.ThrowIfNull(RegolithTimestamp);
ArgumentNullException.ThrowIfNull(BedrockBlockNumber);
ArgumentNullException.ThrowIfNull(CanyonTimestamp);
Copy link
Contributor

Choose a reason for hiding this comment

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

Some of these fields (like CanyonTimestamp) used to be nullable and still are here, but others have changed (like RegolithTimestamp).
Which fields are actually required and which are not?

src/Nethermind/Nethermind.Config/ConfigSourceHelper.cs Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants