feat(bundle): expose Flags/BundleFormat and add serde for downstream integration#23
Draft
czarcas7ic wants to merge 3 commits into
Draft
feat(bundle): expose Flags/BundleFormat and add serde for downstream integration#23czarcas7ic wants to merge 3 commits into
czarcas7ic wants to merge 3 commits into
Conversation
…integration
Let an external transaction serializer reuse Orchard's flag types and consensus
byte encoding instead of re-implementing them. (zebra-chain has its own
transaction codec and currently maintains a parallel `Flags` + a pre/post-NU6.3
"format" enum + byte (de)serialization that must be kept in lock-step with this
crate.)
- Re-export `Flags` and `BundleFormat` from the crate root, alongside the
already-exported `BundleProtocol`.
- Make `Flags::from_parts` public. It keeps cross-address transfers enabled (the
documented safe default); restricted combinations remain reachable via the
existing public constants, so "restricted + spends-disabled" stays
unrepresentable. `from_parts_with_cross_address` stays crate-internal.
- Derive `serde::{Serialize, Deserialize}` on `Flags` so consumers can embed it
in their own serialized types.
With these, an integrator can name the types, construct flags, round-trip the
consensus byte through the existing `Flags::to_byte`/`from_byte(BundleFormat)`,
and serialize flags, with no duplicated logic.
Demonstrates the now-public surface a downstream serializer uses: the
re-exported orchard::{Flags, BundleFormat}, construction via Flags::from_parts,
and a consensus-byte round-trip through to_byte/from_byte.
…otocol Gates the serde derive on Flags: proves pre-NU6.3 and NU6.3 Orchard encode the cross-address bit (0b100) as 0 while NU6.3 Ironwood encodes it as 1, and that a serde round-trip preserves the value (hence the encoded flag byte) for every BundleProtocol. Adds serde_json as a dev-dependency for the round-trip.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Why (draft for review before upstreaming)
Downstream consumers with their own transaction serializer — e.g.
zebra-chain, which does not serialize viazcash_primitives— currently can't reuse this crate's Orchard flag handling, so they re-implement a parallel copy: their ownFlagsbitflags (including the cross-address bit), aFlagFormat { PreNu6_3, Nu6_3 }enum that mirrorsBundleFormat, and the byte (de)serialization. That duplicated, consensus-critical logic has to be kept bit-for-bit in sync with this crate.This crate already has everything needed —
Flags,BundleFormat,to_byte/from_byte, the accessors and constants — it just isn't all reachable/usable from outside. These small changes close the gap so a consumer can delegate, the same wayzcash_primitivesdoes.Changes
FlagsandBundleFormatat the crate root (next toBundleProtocol), so consumers writeorchard::Flags/orchard::BundleFormat.Flags::from_partsmade public — the cross-address-enabled constructor. Restricted sets stay available via the existing public constants (ENABLED,SPENDS_DISABLED,OUTPUTS_DISABLED,CROSS_ADDRESS_DISABLED), so the intentionally-unrepresentable "restricted + spends-disabled" combo stays unreachable from the public API.from_parts_with_cross_addressstays crate-internal.serde::{Serialize, Deserialize}onFlagsso it can be embedded in consumers' serialized types.The byte round-trip (
to_byte/from_byte(BundleFormat)) and the accessors/constants are already public, so no other changes are needed for a consumer to delegate. A doctest onfrom_partsexercises the full public path.serde: tested per protocol
serde_round_trip_preserves_cross_address_bit_per_protocolproves the discriminating cross-address bit (0b100) survives a serde round-trip for everyBundleProtocol: pre-NU6.3 and NU6.3 Orchard encode it as0(reserved /enableCrossAddress = 0), while NU6.3 Ironwood encodes it as1. The existingflags_byte_encodingandflags_parsing_diverges_between_erastests already lock down the consensus byte itself.Open question (feedback wanted)
The serde derive uses the obvious struct-of-three-bools representation. Two things to decide:
derive(Deserialize)can construct the "restricted + spends-disabled" combination thatfrom_partsintentionally forbids (notefrom_bytecan already produce it, so this is not a new soundness gap). If serde should honor that constructor invariant, a hand-writtenDeserializewould be needed.(Consumers such as zebra currently serialize flags in a bitflags-1.x legacy format; aligning the two representations is a separate consumer-side decision.)
Draft to preview the shape before opening upstream.