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
102 changes: 102 additions & 0 deletions src/Nethermind/Nethermind.Xdc/XdcBlockProducer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-FileCopyrightText: 2025 Demerzel Solutions Limited
// SPDX-License-Identifier: LGPL-3.0-only

using Nethermind.Blockchain;
using Nethermind.Config;
using Nethermind.Consensus;
using Nethermind.Consensus.Processing;
using Nethermind.Consensus.Producers;
using Nethermind.Consensus.Transactions;
using Nethermind.Core;
using Nethermind.Core.Crypto;
using Nethermind.Core.Specs;
using Nethermind.Evm.State;
using Nethermind.Evm.Tracing;
using Nethermind.Int256;
using Nethermind.Logging;
using Nethermind.Xdc.RLP;
using Nethermind.Xdc.Spec;
using Nethermind.Xdc.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Nethermind.Xdc;
internal class XdcBlockProducer : BlockProducerBase
{
private readonly IEpochSwitchManager epochSwitchManager;
private readonly ISnapshotManager snapshotManager;
private readonly XdcContext xdcContext;
private readonly ISealer sealer;
private readonly ISpecProvider specProvider;
private readonly ILogManager logManager;
private static readonly ExtraConsensusDataDecoder _extraConsensusDataDecoder = new();

public XdcBlockProducer(IEpochSwitchManager epochSwitchManager, ISnapshotManager snapshotManager, XdcContext xdcContext, ITxSource txSource, IBlockchainProcessor processor, ISealer sealer, IBlockTree blockTree, IWorldState stateProvider, IGasLimitCalculator? gasLimitCalculator, ITimestamper? timestamper, ISpecProvider specProvider, ILogManager logManager, IDifficultyCalculator? difficultyCalculator, IBlocksConfig? blocksConfig) : base(txSource, processor, sealer, blockTree, stateProvider, gasLimitCalculator, timestamper, specProvider, logManager, difficultyCalculator, blocksConfig)
{
this.epochSwitchManager = epochSwitchManager;
this.snapshotManager = snapshotManager;
this.xdcContext = xdcContext;
this.sealer = sealer;
this.specProvider = specProvider;
this.logManager = logManager;
}

protected override BlockHeader PrepareBlockHeader(BlockHeader parent, PayloadAttributes? payloadAttributes)
{
if (parent is not XdcBlockHeader xdcParent)
throw new ArgumentException("Only XDC header are supported.");

QuorumCertificate highestCert = xdcContext.HighestQC;
var currentRound = xdcContext.CurrentRound;

//TODO maybe some sanity checks here for round and hash

byte[] extra = [2, .. _extraConsensusDataDecoder.Encode(new ExtraFieldsV2(currentRound, highestCert)).Bytes];

Address blockAuthor = sealer.Address;
XdcBlockHeader xdcBlockHeader = new(
parent.Hash!,
Keccak.OfAnEmptySequenceRlp,
blockAuthor,
UInt256.Zero,
parent.Number + 1,
XdcConstants.TargetGasLimit,
0,
extra)
{
Author = blockAuthor,
};

IXdcReleaseSpec spec = specProvider.GetXdcSpec(xdcBlockHeader, currentRound);

xdcBlockHeader.Timestamp = parent.Timestamp + (ulong)spec.MinePeriod;

parent.Difficulty = 1;

xdcBlockHeader.BaseFeePerGas = BaseFeeCalculator.Calculate(parent, spec);

if (epochSwitchManager.IsEpochSwitch(xdcBlockHeader, out _))
{
(Address[] masternodes, Address[] penalties) = snapshotManager.CalculateNextEpochMasternodes(xdcBlockHeader, spec);

xdcBlockHeader.Validators = new byte[masternodes.Length * Address.Size];

for (int i = 0; i < masternodes.Length; i++)
{
Array.Copy(masternodes[i].Bytes, 0, xdcBlockHeader.Validators, i * Address.Size, Address.Size);
}

xdcBlockHeader.Penalties = new byte[penalties.Length * Address.Size];

for (int i = 0; i < penalties.Length; i++)
{
Array.Copy(penalties[i].Bytes, 0, xdcBlockHeader.Penalties, i * Address.Size, Address.Size);
}
}
return xdcBlockHeader;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would it make sense to:
Have some base or helper method taking in generic for actual header type.
Reusing base implementation to fill the basic stuff.
Only ammend custom stuff in this method?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

In this case there is very little work saved, since the constructor will set most of the fields and other fields has to be overridden in the XDC version.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

To be honest I'm more concern about future changes that could be auto-applied for XDC and here will have to be manually ported

}
2 changes: 2 additions & 0 deletions src/Nethermind/Nethermind.Xdc/XdcConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ internal static class XdcConstants

public static readonly int InMemoryRound2Epochs = 65536; // One epoch ~ 0.5h, 65536 epochs ~ 3.7y, ~10MB memory

public const long TargetGasLimit = 84000000; // XDC default gas limit per block

// --- Compile-time constants ---
public const int InMemorySnapshots = 128; // Number of recent vote snapshots to keep in memory
public const int BlockSignersCacheLimit = 9000;
Expand Down