-
Notifications
You must be signed in to change notification settings - Fork 720
fix(xdc): restore the XDCX special-transaction window on Apothem and mainnet #12872
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
Changes from 1 commit
f48b896
03753f3
f82ef4e
b14796f
0c2fcc3
7e6f659
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| // SPDX-FileCopyrightText: 2026 Demerzel Solutions Limited | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| using System.IO; | ||
| 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; | ||
|
|
||
| /// <summary> | ||
| /// Pins the system contract addresses our chain specs deserialize into <see cref="XdcChainSpecEngineParameters"/>. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// A key that does not match its property name deserializes to <c>null</c> instead of failing, and the affected | ||
| /// contract then never matches a transaction recipient - the DEX/lending addresses silently lose their | ||
| /// special-transaction handling, which diverges from the reference client. | ||
| /// </remarks> | ||
| [TestFixture, Parallelizable(ParallelScope.All)] | ||
| public class XdcChainSpecTests | ||
| { | ||
| [TestCase("xdc.json", TestName = "mainnet")] | ||
| [TestCase("xdc-testnet.json", TestName = "apothem")] | ||
| public void System_contract_addresses_are_deserialized(string chainSpecFile) | ||
| { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Low — the test pins seven constants, but not the bug class. The root cause is that A cheap generic guard that would have caught // every key under engine.XDPoS.params must bind to a property
foreach (string key in keysFromJson)
Assert.That(typeof(XdcChainSpecEngineParameters).GetProperty(key,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase), Is.Not.Null, key);( Related observation while checking this (pre-existing, not for this PR): |
||
| XdcChainSpecEngineParameters engineParameters = LoadEngineParameters(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"))); | ||
| }); | ||
| } | ||
|
|
||
| private static XdcChainSpecEngineParameters LoadEngineParameters(string chainSpecFile) | ||
| { | ||
| string path = Path.Combine(TestContext.CurrentContext.WorkDirectory, "../../../../", "Chains", chainSpecFile); | ||
| ChainSpec chainSpec = new ChainSpecFileLoader(new EthereumJsonSerializer(), LimboLogs.Instance).LoadEmbeddedOrFromFile(path); | ||
|
|
||
| return chainSpec.EngineChainSpecParametersProvider.GetChainSpecParameters<XdcChainSpecEngineParameters>(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Low — duplicated chainspec loader. These three lines are verbatim Not a correctness issue; the path pattern is the established one ( |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Medium — the divergence window is only half closed by this rename.
IsTIPXDCXReceiveris baked into each release spec fromreleaseStartBlock:but
TIPXDCXReceiverDisable(andTipXDCX,TIPXDCXMinerDisable) are not registered inXdcChainSpecEngineParameters.AddTransitions, so the flag can only flip on whichever unrelated transition encloses the block — the exact caveat already documented forDynamicGasLimitBlockatXdcChainSpecEngineParameters.cs:110.Concretely:
TIPXDCXReceiverDisable66,825,000TIPXDCXReceiverDisable80,370,900TIPXDCXMinerDisable80,370,000TipXDCX(23,779,191 / 38,383,838) does coincide witheip152Transition, so activation is fine — only deactivation is late.Net effect of this PR on Apothem: trading txs to
0x…91go from "never special" (wrong for 23,779,191–66,824,999) to "special up to 71,549,999" (wrong for 66,825,000–71,549,999). Strictly better, but the special-transaction path still diverges from the reference client, which evaluatesTIPXDCXReceiverper block. The lending / trading-state keys (0x…92–0x…94) were already spelled correctly, so this part is pre-existing rather than introduced here — but it is the other half of the same bug the PR description sets out to fix.Suggested fix (same shape as the existing
DynamicGasLimitBlockhandling), plus a spec-provider test case pinningIsTIPXDCXReceiverat 66,825,000 and at 66,824,999:If you'd rather keep this PR minimal, a follow-up issue plus a note here is fine — but as it stands the PR body's claim of parity with the reference client on Apothem DEX handling doesn't hold for blocks ≥ 66,825,000.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Confirmed and folded into this PR in 03753f3 — thanks, this was the more consequential half.
Verified your analysis against the chainspec transition sets independently: activation lands on a transition on both chains, deactivation does not, except Apothem
TIPXDCXMinerDisable61,290,000 which coincides witheip1559Transition.AddTransitionsnow registers all three blocks, following theDynamicGasLimitBlockprecedent.XdcChainSpecTests.XDCX_flags_flip_on_their_own_blockspins the boundaries, deriving them from the engine parameters so the numbers stay in one place (the schedule itself is already pinned to the reference client byXdcForkIdConformanceTests). Without the fix it fails with exactly the spread you predicted: 2 assertions on mainnet, 1 on apothem. Full suite green at 621 tests, and the fork IDs are unperturbed.Findings 2 and 3 I left alone deliberately: the duplicated loader is three lines, and the unmapped-key guard needs
rewardCheckpointresolved first. Both are noted in the PR body as follow-ups.