diff --git a/src/Nethermind/Chains/xdc-testnet.json b/src/Nethermind/Chains/xdc-testnet.json index 4c1dbc14afa..f189a095b71 100644 --- a/src/Nethermind/Chains/xdc-testnet.json +++ b/src/Nethermind/Chains/xdc-testnet.json @@ -142,7 +142,7 @@ "masternodeVotingContract": "0x0000000000000000000000000000000000000088", "blockSignerContract": "0x0000000000000000000000000000000000000089", "randomizeSMCBinary": "0x0000000000000000000000000000000000000090", - "XDCXAddrBinary": "0x0000000000000000000000000000000000000091", + "XDCXAddressBinary": "0x0000000000000000000000000000000000000091", "tradingStateAddressBinary": "0x0000000000000000000000000000000000000092", "XDCXLendingAddressBinary": "0x0000000000000000000000000000000000000093", "XDCXLendingFinalizedTradeAddressBinary": "0x0000000000000000000000000000000000000094" diff --git a/src/Nethermind/Nethermind.Xdc.Test/XdcChainSpecTests.cs b/src/Nethermind/Nethermind.Xdc.Test/XdcChainSpecTests.cs new file mode 100644 index 00000000000..56a726fc4a0 --- /dev/null +++ b/src/Nethermind/Nethermind.Xdc.Test/XdcChainSpecTests.cs @@ -0,0 +1,68 @@ +// SPDX-FileCopyrightText: 2026 Demerzel Solutions Limited +// SPDX-License-Identifier: LGPL-3.0-only + +using Nethermind.Core; +using Nethermind.Logging; +using Nethermind.Serialization.Json; +using Nethermind.Specs.ChainSpecStyle; +using Nethermind.Xdc.Spec; +using NUnit.Framework; + +namespace Nethermind.Xdc.Test; + +/// +/// Pins what our chain specs produce for the XDCX special-transaction path on both networks. +/// +[TestFixture, Parallelizable(ParallelScope.All)] +public class XdcChainSpecTests +{ + [TestCase("xdc.json")] + [TestCase("xdc-testnet.json")] + public void System_contract_addresses_are_deserialized(string chainSpecFile) + { + XdcChainSpecEngineParameters engineParameters = EngineParameters(LoadChainSpec(chainSpecFile)); + + Assert.Multiple(() => + { + Assert.That(engineParameters.MasternodeVotingContract, Is.EqualTo(new Address("0x0000000000000000000000000000000000000088"))); + Assert.That(engineParameters.BlockSignerContract, Is.EqualTo(new Address("0x0000000000000000000000000000000000000089"))); + Assert.That(engineParameters.RandomizeSMCBinary, Is.EqualTo(new Address("0x0000000000000000000000000000000000000090"))); + Assert.That(engineParameters.XDCXAddressBinary, Is.EqualTo(new Address("0x0000000000000000000000000000000000000091"))); + Assert.That(engineParameters.TradingStateAddressBinary, Is.EqualTo(new Address("0x0000000000000000000000000000000000000092"))); + Assert.That(engineParameters.XDCXLendingAddressBinary, Is.EqualTo(new Address("0x0000000000000000000000000000000000000093"))); + Assert.That(engineParameters.XDCXLendingFinalizedTradeAddressBinary, Is.EqualTo(new Address("0x0000000000000000000000000000000000000094"))); + }); + } + + [TestCase("xdc.json")] + [TestCase("xdc-testnet.json")] + public void XDCX_flags_flip_on_their_own_blocks(string chainSpecFile) + { + ChainSpec chainSpec = LoadChainSpec(chainSpecFile); + XdcChainSpecEngineParameters engineParameters = EngineParameters(chainSpec); + XdcChainSpecBasedSpecProvider specProvider = new(chainSpec, engineParameters, LimboLogs.Instance); + + ulong activation = engineParameters.TipXDCX!.Value; + ulong minerDisable = engineParameters.TIPXDCXMinerDisable!.Value; + ulong receiverDisable = engineParameters.TIPXDCXReceiverDisable!.Value; + + Assert.Multiple(() => + { + Assert.That(specProvider.GetXdcSpec(activation - 1).IsTIPXDCXMiner, Is.False); + Assert.That(specProvider.GetXdcSpec(activation).IsTIPXDCXMiner, Is.True); + Assert.That(specProvider.GetXdcSpec(minerDisable - 1).IsTIPXDCXMiner, Is.True); + Assert.That(specProvider.GetXdcSpec(minerDisable).IsTIPXDCXMiner, Is.False); + + Assert.That(specProvider.GetXdcSpec(activation - 1).IsTIPXDCXReceiver, Is.False); + Assert.That(specProvider.GetXdcSpec(activation).IsTIPXDCXReceiver, Is.True); + Assert.That(specProvider.GetXdcSpec(receiverDisable - 1).IsTIPXDCXReceiver, Is.True); + Assert.That(specProvider.GetXdcSpec(receiverDisable).IsTIPXDCXReceiver, Is.False); + }); + } + + private static ChainSpec LoadChainSpec(string chainSpecFile) => + new ChainSpecFileLoader(new EthereumJsonSerializer(), LimboLogs.Instance).LoadEmbeddedOrFromFile(chainSpecFile); + + private static XdcChainSpecEngineParameters EngineParameters(ChainSpec chainSpec) => + chainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); +} diff --git a/src/Nethermind/Nethermind.Xdc.Test/XdcForkIdConformanceTests.cs b/src/Nethermind/Nethermind.Xdc.Test/XdcForkIdConformanceTests.cs index a3f03ed1bc7..25133c1d3c0 100644 --- a/src/Nethermind/Nethermind.Xdc.Test/XdcForkIdConformanceTests.cs +++ b/src/Nethermind/Nethermind.Xdc.Test/XdcForkIdConformanceTests.cs @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2026 Demerzel Solutions Limited // SPDX-License-Identifier: LGPL-3.0-only -using System.IO; using Nethermind.Core; using Nethermind.Core.Crypto; using Nethermind.Core.Test.Builders; @@ -65,8 +64,7 @@ private static void AssertForkId(string chainSpecFile, Hash256 genesisHash, ulon private static XdcForkInfo ForkInfo(string chainSpecFile, Hash256 genesisHash) { - string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "../../../../", "Chains", chainSpecFile); - ChainSpec chainSpec = new ChainSpecFileLoader(new EthereumJsonSerializer(), LimboLogs.Instance).LoadEmbeddedOrFromFile(path); + ChainSpec chainSpec = new ChainSpecFileLoader(new EthereumJsonSerializer(), LimboLogs.Instance).LoadEmbeddedOrFromFile(chainSpecFile); XdcChainSpecEngineParameters engineParameters = chainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters(); diff --git a/src/Nethermind/Nethermind.Xdc/Spec/XdcChainSpecEngineParameters.cs b/src/Nethermind/Nethermind.Xdc/Spec/XdcChainSpecEngineParameters.cs index c5e86ce654b..b534ac1f9f0 100644 --- a/src/Nethermind/Nethermind.Xdc/Spec/XdcChainSpecEngineParameters.cs +++ b/src/Nethermind/Nethermind.Xdc/Spec/XdcChainSpecEngineParameters.cs @@ -109,6 +109,12 @@ public void AddTransitions(SortedSet blockNumbers, SortedSet times // Without its own release spec boundary the flag would only flip on whichever transition encloses it. if (DynamicGasLimitBlock is not null) blockNumbers.Add(DynamicGasLimitBlock.Value); + if (TipXDCX is not null) + blockNumbers.Add(TipXDCX.Value); + if (TIPXDCXMinerDisable is not null) + blockNumbers.Add(TIPXDCXMinerDisable.Value); + if (TIPXDCXReceiverDisable is not null) + blockNumbers.Add(TIPXDCXReceiverDisable.Value); } }