You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This change updates ElectrumX's Zcash support from the legacy Sapling-only
deserializer to the transaction formats used by the modern Zcash chain,
including NU5, NU6, NU6.1, NU6.2, and NU6.3 (Ironwood / ZIP-258). It also
adds a Zebra-specific daemon adapter and makes the Zcash coin use it.
Zcash transaction deserialization
Added parsing of Zcash v5 and v6 transaction encodings.
Added ZIP-244-style transaction ID construction, including the transparent,
Sapling, Orchard, and v6 Ironwood digest components.
Preserved ElectrumX's transparent transaction projection: inputs, outputs,
scripts, locktime, and transaction ID are available to the indexer while
shielded data is consumed only as required to find transaction boundaries
and calculate the transaction ID.
Added shielded value-balance accounting to the mempool fee calculation, so
fees for Zcash transactions with shielded bundles are calculated correctly.
Added strict bounds and canonical CompactSize validation for the new
Zcash-specific reader.
Added fixtures and unit coverage from mainnet transactions around NU5 and
NU6.3 activation boundaries, as well as v5/v6 transparent input/output and
transaction-ID checks.
ZIP-233 boundary
The v6 parser implements the currently deployed NU6.3 layout. ZIP-233 is
not currently enabled by Zebra. When that future consensus change is
activated, an eight-byte zip233Amount is inserted in the v6 header and must
be included in the header digest and deducted from the fee adjustment. The
code documents this explicitly so that a future activation cannot silently
produce an incorrect parse or transaction ID.
Zebra RPC compatibility
ZcashZebraDaemon isolates Zebra-specific JSON-RPC behaviour from domain
logic:
Sends JSON-RPC 2.0 requests and always includes params, including an
empty parameter list.
Normalizes Zebra's JSON-RPC 2.0 response envelope to the response shape
expected by existing ElectrumX daemon code.
Uses numeric getblock verbosity (0 for raw blocks, 1 for decoded
blocks), which Zebra requires.
Preserves batch response ordering by JSON-RPC request ID.
Returns Electrum's standard -1 sentinel for fee estimates because Zebra
does not expose an equivalent fee-estimation RPC.
The adapter is intentionally Zebra-oriented. zcashd has a more legacy RPC
interface and different operational assumptions; deployments that use zcashd
should use a separately verified zcashd adapter/configuration rather than
assuming every Zebra workaround is required there. In particular, the
current upstream zcashd codebase does not support the NU6.3 mainnet upgrade,
so it cannot synchronize the current mainnet regardless of RPC envelope
compatibility.
Bounded block fetching
Zebra rejects oversized JSON-RPC batch responses. Raw blocks are
hex-encoded in RPC responses, making response payloads roughly twice the raw
block byte size. The Zcash max_fetch_blocks() policy now uses explicit
height ranges and conservative batch limits derived from full-mainnet block
size measurements, targeting a 35 MB response budget below Zebra's 50 MiB
limit. The former fixed batch size of 10 remains in a comment for reference.
Electrum protocol version: 1.5.2
The normal ElectrumX session class supports protocol versions through
1.7.0. ZcashElectrumX deliberately advertises a maximum of 1.5.2 when it
is backed directly by Zebra. Zebra does not provide the mempool fee and
recent-transaction information needed to implement the 1.6+ Electrum methods
correctly. Advertising 1.5.2 prevents clients from negotiating methods that
the server cannot faithfully support; it is a Zcash/Zebra-specific limit, not
a global ElectrumX limit.
Tests
Extended deserializer unit tests for v5 and v6 formats, including malformed
encodings and known mainnet transaction IDs.
Added mainnet block and transaction fixtures at upgrade boundaries.
Added daemon adapter tests for Zebra request formatting, response
normalization, verbosity handling, batch ordering, and fetch limits.
Tested this PR against the latest Zebra version. ElectrumX successfully parsed and synchronized the full
blockchain up to the current tip:
INFO:DB:flush took 0.0s. Height 3,481,501 txs: 18,253,118 (+16)
The repository test suite also passes. In addition, I ran integration checks outside this repository
against a live Zebra instance:
Selected the latest 10 blocks containing transparent outputs, extracted their transparent addresses, and
compared balances obtained via Zebra RPC with balances returned by ElectrumX. The results matched.
Selected transactions immediately before, at, and after multiple Network Upgrade activation heights.
Compared their raw transaction hex returned by Zebra and by ElectrumX.
Extracted transparent addresses from those boundary transactions and verified that the relevant
transaction IDs are returned by blockchain.scripthash.get_history for the corresponding addresses.
Performed additional consistency checks intended to confirm that the ElectrumX database reflects the
chain state as seen by Zebra.
This is not a guarantee that the implementation contains no other bugs. The transaction deserialization
logic was also independently reviewed by several AI models against Zebra’s implementation; no deviations
were identified. Everything appears to be working correctly, but additional independent review and testing
of this PR would still be very welcome.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This change updates ElectrumX's Zcash support from the legacy Sapling-only
deserializer to the transaction formats used by the modern Zcash chain,
including NU5, NU6, NU6.1, NU6.2, and NU6.3 (Ironwood / ZIP-258). It also
adds a Zebra-specific daemon adapter and makes the Zcash coin use it.
Zcash transaction deserialization
Sapling, Orchard, and v6 Ironwood digest components.
scripts, locktime, and transaction ID are available to the indexer while
shielded data is consumed only as required to find transaction boundaries
and calculate the transaction ID.
fees for Zcash transactions with shielded bundles are calculated correctly.
Zcash-specific reader.
NU6.3 activation boundaries, as well as v5/v6 transparent input/output and
transaction-ID checks.
ZIP-233 boundary
The v6 parser implements the currently deployed NU6.3 layout. ZIP-233 is
not currently enabled by Zebra. When that future consensus change is
activated, an eight-byte
zip233Amountis inserted in the v6 header and mustbe included in the header digest and deducted from the fee adjustment. The
code documents this explicitly so that a future activation cannot silently
produce an incorrect parse or transaction ID.
Zebra RPC compatibility
ZcashZebraDaemonisolates Zebra-specific JSON-RPC behaviour from domainlogic:
params, including anempty parameter list.
expected by existing ElectrumX daemon code.
getblockverbosity (0for raw blocks,1for decodedblocks), which Zebra requires.
-1sentinel for fee estimates because Zebradoes not expose an equivalent fee-estimation RPC.
The adapter is intentionally Zebra-oriented. zcashd has a more legacy RPC
interface and different operational assumptions; deployments that use zcashd
should use a separately verified zcashd adapter/configuration rather than
assuming every Zebra workaround is required there. In particular, the
current upstream zcashd codebase does not support the NU6.3 mainnet upgrade,
so it cannot synchronize the current mainnet regardless of RPC envelope
compatibility.
Bounded block fetching
Zebra rejects oversized JSON-RPC batch responses. Raw blocks are
hex-encoded in RPC responses, making response payloads roughly twice the raw
block byte size. The Zcash
max_fetch_blocks()policy now uses explicitheight ranges and conservative batch limits derived from full-mainnet block
size measurements, targeting a 35 MB response budget below Zebra's 50 MiB
limit. The former fixed batch size of 10 remains in a comment for reference.
Electrum protocol version: 1.5.2
The normal
ElectrumXsession class supports protocol versions through1.7.0.
ZcashElectrumXdeliberately advertises a maximum of 1.5.2 when itis backed directly by Zebra. Zebra does not provide the mempool fee and
recent-transaction information needed to implement the 1.6+ Electrum methods
correctly. Advertising 1.5.2 prevents clients from negotiating methods that
the server cannot faithfully support; it is a Zcash/Zebra-specific limit, not
a global ElectrumX limit.
Tests
encodings and known mainnet transaction IDs.
normalization, verbosity handling, batch ordering, and fetch limits.