Skip to content

Alternative: replace hand-written FullBlock Streamable with Option3<Program, Bytes> - #1463

Closed
richardkiss wants to merge 3 commits into
full-block-generatorfrom
option3-fullblock
Closed

Alternative: replace hand-written FullBlock Streamable with Option3<Program, Bytes>#1463
richardkiss wants to merge 3 commits into
full-block-generatorfrom
option3-fullblock

Conversation

@richardkiss

Copy link
Copy Markdown
Contributor

Summary

This is an alternative design to #1456, proposed for discussion.

PR #1456 hand-writes 145 lines of Streamable for FullBlock to bit-pack a version flag into the Option prefix byte for transactions_generator. This PR proposes Option3<V1, V2> — a generic tri-state optional type in chia-traits — that lets FullBlock keep #[streamable] with zero hand-written serialization code.

Key Insight

PR #1456 appears to have four states (0b00/0b01/0b10/0b11), but there are really only three meaningful states:

  1. No generator (v0 or v1 — identical to parse, since there's nothing there)
  2. v0 Program generator (+ ref_list)
  3. v1 raw bytes generator (no ref_list)

"v0 no generator" and "v1 no generator" are functionally identical at the wire level.

Changes

New type: Option3<V1, V2> in chia-traits

Wire encoding:

  • None0x00
  • Some1(V1)0x01 + V1
  • Some2(V2)0x02 + V2

Backward-compatible with Option<T> for the None/Some cases. New nodes are the only ones that ever see 0x02, and they're hard-fork nodes.

FullBlock fields:

// Before (PR #1456):
transactions_generator: Option<Program>,
transactions_generator_ref_list: Vec<u32>,
transactions_generator_buffer: Option<Vec<u8>>,
version: u8,
// + 145 lines of hand-written Streamable

// After (this PR):
transactions_generator: Option3<Program, Bytes>,
transactions_generator_ref_list: Option<Vec<u32>>,  // None = v1, Some = v0
// + #[streamable] — zero hand-written code

Version detection: is_v1()transactions_generator_ref_list.is_none()

Wire Format

Differs from #1456 by +1 byte per block (the Option prefix on ref_list). For a hard fork protocol change, this overhead is negligible — typical blocks are KB to MB.

Trade-offs

This PR PR #1456
Hand-written serialization 0 lines 145 lines
Wire overhead vs current +1 byte/block 0 bytes
Type safety Can't set both Program + Bytes Can set both (runtime validation needed)
Reusability Option3 usable anywhere One-off FullBlock impl

Tests

10 Rust tests covering v0/v1 roundtrips, prefix byte encoding, and ref_list presence. All passing.

Opened as draft for discussion — would love your thoughts on the 1-byte overhead trade-off vs. eliminating the hand-written impl.

Made with Cursor

@richardkiss
richardkiss force-pushed the option3-fullblock branch 3 times, most recently from 6dcb672 to bc3c268 Compare June 5, 2026 19:10
Add Option3<V1, V2> to chia-traits: a tri-state optional type with wire
encoding 0x00/0x01/0x02. Use it for FullBlock.transactions_generator to
cleanly express three states (no generator / v0 Program / v1 raw bytes)
without hand-written serialization code.

transactions_generator_ref_list changes from Vec<u32> to Option<Vec<u32>>:
None signals v1 format (ref_list omitted), Some signals v0 format.

This replaces the 145-line hand-written Streamable impl in PR #1456 with
a #[streamable] derive and zero hand-written serialization code. The wire
format differs by 1-2 bytes per block (negligible for a hard fork protocol
change).

Co-authored-by: Cursor <cursoragent@cursor.com>
…rator field

Co-authored-by: Cursor <cursoragent@cursor.com>
@richardkiss

Copy link
Copy Markdown
Contributor Author

Closing in favor of Arvid's #1456 (approved). The Option3 approach was an experiment to show we could avoid hand-rolled Streamable, but #1456 is the path forward for HF2 FullBlock wire format.

@richardkiss richardkiss closed this Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants