Skip to content

refactor(core/vm): remove unused privacy precompiles and the privacy package, close #2895 - #2898

Open
gzliudan wants to merge 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:remove-privacy-package
Open

gzliudan wants to merge 1 commit into
XinFinOrg:dev-upgradefrom
gzliudan:remove-privacy-package

Conversation

@gzliudan

@gzliudan gzliudan commented Oct 25, 2026 •

Copy link
Copy Markdown
Collaborator

Close #2895

Proposed changes

core/vm/privacy (Monero-style RingCT ring signatures + Bulletproofs range proofs, TomoChain lineage) was reachable only through two precompiled contracts — RING_SIG_VERIFY at 0x…001e and BULLET_PROOF_VERIFY at 0x…0028 — restored on 2024-03-07 in #477 for a devnet privacy experiment. Nothing else imports the package. This PR deletes the package, both verifier types and both table registrations.

 core/vm/
-├── privacy/
-│   ├── bulletproof.go           (1372)
-│   ├── bulletproof.json
-│   ├── bulletproof_test.go       (464)
-│   ├── ringct.go                 (621)
-│   └── ringct_test.go            (329)
 ├── contracts.go              -50  (-privacy import, -0x1e/-0x28 in 2 buckets, -2 verifier types)
 ├── contracts_test.go          -2  (allPrecompiles table)
 └── precompile_sets_test.go    ±5  (byzantium/istanbul XDCx bucket pinned at 0x29/0x2a only)
 go.mod / go.sum                    -github.com/btcsuite/btcd/btcec/v2 v2.2.0

10 files, +2 −2845. core/vm/privacy was the last consumer of btcec/v2, so the module drops out of the dependency graph with it.

Where the two precompiles were reachable

Both are registered only in the Byzantium and Istanbul tables. activePrecompiledContracts (core/vm/contracts.go:223) evaluates Osaka → Prague → EIP1559 → IsXDCxDisable → Istanbul → Byzantium, so the switch to the XDCv2 table — not the EIP1559 fork — is what makes them unreachable:

Network Byzantium Istanbul TIPXDCXMinerDisableBlock (table → XDCv2) EIP1559 Head (2026-11-01) Window where 0x1e / 0x28 are precompiles
XDC mainnet (50) 4 38,383,838 80,370,000 98,800,200 108,943,608 [4, 80,369,999]
Apothem (51) 4 23,779,191 61,290,000 71,550,000 84,823,432 [4, 61,289,999]

Devnet (551) and localnet (5151) set TIPXDCXMinerDisableBlock = 0, so the XDCv2 table — which has never contained these addresses — is active from genesis there.

Historical replay still selects the Byzantium/Istanbul tables below that block, so consensus neutrality has to hold across the entire window, not just the tail after EIP1559.

Why replay is the decisive test

Both contracts are pure verifiers: no state write, no log, no event. The only on-chain footprint of a hit is the fixed 100,000 gas charge (RequiredGas returns a constant). A binary without them treats 0x1e/0x28 as ordinary empty accounts (~700 gas, 2,600 if cold), so any call produces a ~97k gasUsed delta → different sender balance and coinbase credit → different state root. Explorer history is therefore supporting evidence only; a genesis full-sync replay with the removal build plus per-block ValidateState is the authoritative check.

Evidence

Existing explorers. Five reachable explorers across two independent indexer stacks (Etherscan-built and OpenScan-built) report zero transactions, zero internal transactions and zero balance for both addresses across all history of mainnet and Apothem — xdcscan.com, xdcscan.io, testnet.xdcscan.com, apothem.xdcscan.io, explorer.apothem.network (checked 2026-10-25; apothem.blocksscan.io was offline that day). Full table in #2895.

Apothem replay — done. A fresh Apothem archive node was synced from genesis with a binary built from the removal commit itself (440466ea; running image md5 d29dc78a…, and strings on the live process contains none of RING_SIG_VERIFY, BULLET_PROOF_VERIFY, ring signature, bulletproof, RingCT):

  • fresh datadir created 2026-10-25 20:16 CST, single process, --syncmode full --gcmode archive, no restart since
  • first imported segment number=15 blocks=15; head 72,278,038 on 2026-11-01 19:45 CST, i.e. well past TIPXDCXMinerDisableBlock (61,290,000)
  • every block went through ValidateState; 0 ERROR / CRIT / PANIC across ~2.9M log lines, and the only mismatch match is the unrelated startup check Resolved chain config mismatch policy

That run replayed [1, 61,289,999] with the precompiles compiled out and never diverged, so the removal is empirically consensus-neutral on Apothem.

Mainnet replay — pending. The mainnet archive node is at 51,349,606, still short of 80,370,000. Per the proposal in #2895 this replay has to pass before the removal reaches mainnet, so this PR is gated on it rather than on the Apothem result alone.

Build and CI. make all clean; go test ./core/vm/... passes (TestPrecompileSetsByFork now pins the byzantium/istanbul XDCx bucket at the two price precompiles that remain); golangci-lint run --new-from-rev=68b1ea2cab 0 new issues (2 revive findings in XDCx_price.go pre-exist on dev-upgrade); make tidy leaves no untidy module files. CI: 9 test shards, 4 race shards + race rpc, and lint all green.

Merge Danger

Door: two-way at the code level (clean revert), one-way once a node runs it over history

If the zero-call evidence were wrong, a full-sync node would diverge at the first historical block that calls either address. The failure is loud (ValidateState rejection, not silent corruption), but it is a consensus event on a live chain and would only surface on nodes replaying the affected window.

Blast Radius: consensus (historical replay below TIPXDCXMinerDisableBlock)

Types of changes

What types of changes does your code introduce to XDC network?
Put an ✅ in the boxes that apply

  • refactor: A code change that neither fixes a bug nor adds a feature

Impacted Components

Which parts of the codebase does this PR touch?
Put an ✅ in the boxes that apply

  • Consensus
  • Geth

Checklist

Put an ✅ in the boxes once you have confirmed below actions (or provide reasons on not doing so) that

  • This PR has sufficient test coverage (unit/integration test) OR I have provided reason in the PR description for not having test coverage — unit coverage updated; the decisive validation is the genesis replay tracked in core/vm: remove unused privacy precompiles and the privacy package #2895 (Apothem done, mainnet pending)
  • Tested on a private network from the genesis block and monitored the chain operating correctly for multiple epochs.
  • Provide an end-to-end test plan in the PR description on how to manually test it on the devnet/testnet.
  • Tested the backwards compatibility.
  • Tested with XDC nodes running this version co-exist with those running the previous version.
  • Relevant documentation has been updated as part of this PR
  • N/A — behaviour-preserving removal; the window analysis, the gas-delta argument and the replay results above substitute for the manual test items

@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fcb28d1b-0d62-45a8-a669-d1b40135fe79

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@gzliudan gzliudan added the WIP work in process label Oct 25, 2026
@gzliudan
gzliudan force-pushed the remove-privacy-package branch 2 times, most recently from 7f68d9d to 6cd5452 Compare October 26, 2026 05:33
…package, close XinFinOrg#2895

The Monero-style RingCT ring signature and Bulletproof range proof package
arrived with the TomoChain lineage and was restored on 2024-03-07 (PR XinFinOrg#477)
to support a devnet privacy experiment. It was reachable only through two
precompiled contracts, RING_SIG_VERIFY at 0x1e and BULLET_PROOF_VERIFY at
0x28, registered solely in the Byzantium and Istanbul precompile tables.

Neither precompile has ever been called on a live network: both become
unreachable once a chain passes its EIP1559 fork, mainnet (~108.7M) and
Apothem (~84.5M) are well past theirs, and six independent explorers
(two indexer stacks) report zero transactions, zero internal transactions
and zero balance for both addresses across all history. Evidence is
archived in issue XinFinOrg#2895.

Remove the package, the two table registrations and the verifier types,
drop the matching test-table entries, and pin the byzantium/istanbul XDCx
bucket expectation at the two price precompiles that remain. The package
was the last consumer of btcsuite/btcd/btcec/v2, so the module drops out
of go.mod/go.sum with it. Historical replay still exercises the Byzantium
and Istanbul windows, so consensus neutrality rests on the zero-call
evidence above; the full replay validation tracked in XinFinOrg#2895 is the gate
before this reaches mainnet.

Close XinFinOrg#2895
@gzliudan
gzliudan force-pushed the remove-privacy-package branch from d05b95d to f8d0fdb Compare November 4, 2026 17:20

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WIP work in process

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants