Skip to content

Implement to_data for block and transaction views.#1905

Merged
evoskuil merged 2 commits into
libbitcoin:masterfrom
echennells:block-view-to-data
Jul 9, 2026
Merged

Implement to_data for block and transaction views.#1905
evoskuil merged 2 commits into
libbitcoin:masterfrom
echennells:block-view-to-data

Conversation

@echennells

Copy link
Copy Markdown
Contributor

block_view::to_data(writer&, bool) was an unimplemented stub (it asserted "not implemented"), so a block_view could report its serialized size but not emit its bytes; transaction_view had no to_data at all. This implements both, with witness stripping.

Witness can be downgraded but never added, mirroring chain::transaction: a witness = true call on a witnessed view writes the held bytes; otherwise the witness is stripped on write. block_view::to_data mirrors serialized_size: the witnessed form is the original buffer (a single write), otherwise it writes the header, the transaction count, and each transaction view stripped.

Round-trip tests assert the view serializes identically to the equivalent chain::block for witnessed, non-witness and stripped-source blocks. Full system test suite green.

Comment thread src/chain/views/block_view.cpp Outdated

// Strip witness: the header and transaction count are unaffected.
sink.write_bytes({ buffer_->data(), std::next(buffer_->data(),
header::serialized_size()) });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use

void write_bytes(const uint8_t* data, size_t size) NOEXCEPT override;

Comment thread src/chain/views/transaction_view.cpp Outdated
// Witness can be stripped but never added (mirrors chain::transaction).
if (witness && is_segregated())
{
sink.write_bytes({ tx_ptr_, std::next(tx_ptr_, size_) });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use

 void write_bytes(const uint8_t* data, size_t size) NOEXCEPT override;

Comment thread test/chain/views/block_view.cpp Outdated
// One segregated (witness) transaction and one legacy (non-witness)
// transaction in a single block, so the per-transaction witness strip is
// exercised both ways within one to_data(false) call.
const block mixed

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to /mocks/blocks.*

uint32_t version() const NOEXCEPT;
uint32_t locktime() const NOEXCEPT;
size_t serialized_size(bool witness) const NOEXCEPT;
void to_data(writer& sink, bool witness) const NOEXCEPT;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move up to own section and add complete complement of overloads (see block_view and all chain:: objects):

    /// Serialization.
    data_chunk to_data(bool witness) const NOEXCEPT;
    void to_data(std::ostream& stream, bool witness) const NOEXCEPT;
    void to_data(writer& sink, bool witness) const NOEXCEPT;

Comment thread src/chain/views/transaction_view.cpp Outdated
sink.write_bytes({ tx_ptr_, std::next(tx_ptr_, version_size) });
sink.write_bytes({ body, body_end });
sink.write_bytes({ std::next(tx_ptr_, size_ - locktime_size),
std::next(tx_ptr_, size_) });

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here... if you are going to do pointer and size math, use the pointer/size overload, avoiding the unnecessary intermediate data_slice.

block_view::to_data(writer&, bool) was an unimplemented stub, so a block_view
could report its serialized size but not emit its bytes; transaction_view had
no to_data at all.

Implement transaction_view::to_data to write the view, stripping the witness
when requested: witness can be downgraded but never added (mirroring
chain::transaction), so a witness-true call on a segregated view writes the
held bytes, and otherwise the marker and flag sentinels and the witness data
are dropped while version, inputs, outputs and locktime are written unchanged.

Implement block_view::to_data as the twin of serialized_size: the witnessed
form is the original buffer, otherwise write the header and transaction count
and strip each transaction view. Add round-trip tests asserting each view
serializes identically to the equivalent chain::block or chain::transaction
for witnessed, non-witness and stripped-source cases, including a
multi-transaction block.
…tion_view serialization section, block2c mock, overload test.
@echennells
echennells force-pushed the block-view-to-data branch from ef1f00e to 681552b Compare July 9, 2026 05:18
@evoskuil
evoskuil merged commit 71862e0 into libbitcoin:master Jul 9, 2026
15 of 29 checks passed
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