Bitcoin ABC 0.33.12
P2P Digital Currency
streams.h
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2016 The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#ifndef BITCOIN_STREAMS_H
7#define BITCOIN_STREAMS_H
8
9#include <serialize.h>
10#include <span.h>
12#include <util/overflow.h>
13
14#include <algorithm>
15#include <cassert>
16#include <cstdint>
17#include <cstdio>
18#include <cstring>
19#include <ios>
20#include <limits>
21#include <optional>
22#include <string>
23#include <utility>
24#include <vector>
25
32public:
39 VectorWriter(std::vector<uint8_t> &vchDataIn, size_t nPosIn)
40 : vchData{vchDataIn}, nPos{nPosIn} {
41 if (nPos > vchData.size()) {
42 vchData.resize(nPos);
43 }
44 }
49 template <typename... Args>
50 VectorWriter(std::vector<uint8_t> &vchDataIn, size_t nPosIn, Args &&...args)
51 : VectorWriter(vchDataIn, nPosIn) {
52 ::SerializeMany(*this, std::forward<Args>(args)...);
53 }
55 assert(nPos <= vchData.size());
56 size_t nOverwrite = std::min(src.size(), vchData.size() - nPos);
57 if (nOverwrite) {
58 memcpy(vchData.data() + nPos, src.data(), nOverwrite);
59 }
60 if (nOverwrite < src.size()) {
61 vchData.insert(vchData.end(), UCharCast(src.data()) + nOverwrite,
62 UCharCast(src.end()));
63 }
64 nPos += src.size();
65 }
66 template <typename T> VectorWriter &operator<<(const T &obj) {
67 ::Serialize(*this, obj);
68 return (*this);
69 }
70
71private:
72 std::vector<uint8_t> &vchData;
73 size_t nPos;
74};
75
80private:
82
83public:
88
89 template <typename T> SpanReader &operator>>(T &obj) {
90 ::Unserialize(*this, obj);
91 return (*this);
92 }
93
94 size_t size() const { return m_data.size(); }
95 bool empty() const { return m_data.empty(); }
96
98 if (dst.size() == 0) {
99 return;
100 }
101
102 // Read from the beginning of the buffer
103 if (dst.size() > m_data.size()) {
104 throw std::ios_base::failure("SpanReader::read(): end of data");
105 }
106 memcpy(dst.data(), m_data.data(), dst.size());
107 m_data = m_data.subspan(dst.size());
108 }
109};
110
119protected:
122 vector_type::size_type m_read_pos{0};
123
124public:
125 typedef vector_type::allocator_type allocator_type;
126 typedef vector_type::size_type size_type;
127 typedef vector_type::difference_type difference_type;
128 typedef vector_type::reference reference;
129 typedef vector_type::const_reference const_reference;
130 typedef vector_type::value_type value_type;
131 typedef vector_type::iterator iterator;
132 typedef vector_type::const_iterator const_iterator;
133 typedef vector_type::reverse_iterator reverse_iterator;
134
135 explicit DataStream() = default;
138 : vch(sp.data(), sp.data() + sp.size()) {}
139
140 std::string str() const {
141 return std::string{UCharCast(data()), UCharCast(data() + size())};
142 }
143
144 //
145 // Vector subset
146 //
147 const_iterator begin() const { return vch.begin() + m_read_pos; }
148 iterator begin() { return vch.begin() + m_read_pos; }
149 const_iterator end() const { return vch.end(); }
150 iterator end() { return vch.end(); }
151 size_type size() const { return vch.size() - m_read_pos; }
152 bool empty() const { return vch.size() == m_read_pos; }
154 vch.resize(n + m_read_pos, c);
155 }
156 void reserve(size_type n) { vch.reserve(n + m_read_pos); }
158 return vch[pos + m_read_pos];
159 }
161 void clear() {
162 vch.clear();
163 m_read_pos = 0;
164 }
165 value_type *data() { return vch.data() + m_read_pos; }
166 const value_type *data() const { return vch.data() + m_read_pos; }
167
168 void insert(iterator it, std::vector<value_type>::const_iterator first,
169 std::vector<value_type>::const_iterator last) {
170 if (last == first) {
171 return;
172 }
173
174 assert(last - first > 0);
175 if (it == vch.begin() + m_read_pos &&
176 (unsigned int)(last - first) <= m_read_pos) {
177 // special case for inserting at the front when there's room
178 m_read_pos -= (last - first);
179 memcpy(&vch[m_read_pos], &first[0], last - first);
180 } else {
181 vch.insert(it, first, last);
182 }
183 }
184
185 // This was added to have full compat with the std::vector interface but is
186 // unused (except in a Bitcoin ABC specific test in stream_tests)
187 void insert(iterator it, const value_type *first, const value_type *last) {
188 if (last == first) {
189 return;
190 }
191
192 assert(last - first > 0);
193 if (it == vch.begin() + m_read_pos &&
194 (unsigned int)(last - first) <= m_read_pos) {
195 // special case for inserting at the front when there's room
196 m_read_pos -= (last - first);
197 memcpy(&vch[m_read_pos], &first[0], last - first);
198 } else {
199 vch.insert(it, first, last);
200 }
201 }
202
204 if (it == vch.begin() + m_read_pos) {
205 // special case for erasing from the front
206 if (++m_read_pos >= vch.size()) {
207 // whenever we reach the end, we take the opportunity to clear
208 // the buffer
209 m_read_pos = 0;
210 return vch.erase(vch.begin(), vch.end());
211 }
212 return vch.begin() + m_read_pos;
213 } else {
214 return vch.erase(it);
215 }
216 }
217
219 if (first == vch.begin() + m_read_pos) {
220 // special case for erasing from the front
221 if (last == vch.end()) {
222 m_read_pos = 0;
223 return vch.erase(vch.begin(), vch.end());
224 } else {
225 m_read_pos = (last - vch.begin());
226 return last;
227 }
228 } else {
229 return vch.erase(first, last);
230 }
231 }
232
233 inline void Compact() {
234 vch.erase(vch.begin(), vch.begin() + m_read_pos);
235 m_read_pos = 0;
236 }
237
238 bool Rewind(std::optional<size_type> n = std::nullopt) {
239 // Total rewind if no size is passed
240 if (!n) {
241 m_read_pos = 0;
242 return true;
243 }
244 // Rewind by n characters if the buffer hasn't been compacted yet
245 if (*n > m_read_pos) {
246 return false;
247 }
248 m_read_pos -= *n;
249 return true;
250 }
251
252 //
253 // Stream subset
254 //
255 bool eof() const { return size() == 0; }
256 int in_avail() const { return size(); }
257
259 if (dst.size() == 0) {
260 return;
261 }
262
263 // Read from the beginning of the buffer
264 auto next_read_pos{CheckedAdd(m_read_pos, dst.size())};
265 if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
266 throw std::ios_base::failure("DataStream::read(): end of data");
267 }
268 memcpy(dst.data(), &vch[m_read_pos], dst.size());
269 if (next_read_pos.value() == vch.size()) {
270 m_read_pos = 0;
271 vch.clear();
272 return;
273 }
274 m_read_pos = next_read_pos.value();
275 }
276
277 void ignore(size_t num_ignore) {
278 // Ignore from the beginning of the buffer
279 auto next_read_pos{CheckedAdd(m_read_pos, num_ignore)};
280 if (!next_read_pos.has_value() || next_read_pos.value() > vch.size()) {
281 throw std::ios_base::failure("DataStream::ignore(): end of data");
282 }
283 if (next_read_pos.value() == vch.size()) {
284 m_read_pos = 0;
285 vch.clear();
286 return;
287 }
288 m_read_pos = next_read_pos.value();
289 }
290
292 // Write to the end of the buffer
293 vch.insert(vch.end(), src.begin(), src.end());
294 }
295
296 template <typename T> DataStream &operator<<(const T &obj) {
297 ::Serialize(*this, obj);
298 return (*this);
299 }
300
301 template <typename T> DataStream &operator>>(T &&obj) {
302 ::Unserialize(*this, obj);
303 return (*this);
304 }
305
311 void Xor(const std::vector<uint8_t> &key) {
312 if (key.size() == 0) {
313 return;
314 }
315
316 for (size_type i = 0, j = 0; i != size(); i++) {
317 vch[i] ^= std::byte{key[j++]};
318
319 // This potentially acts on very many bytes of data, so it's
320 // important that we calculate `j`, i.e. the `key` index in this way
321 // instead of doing a %, which would effectively be a division for
322 // each byte Xor'd -- much slower than need be.
323 if (j == key.size()) {
324 j = 0;
325 }
326 }
327 }
328};
329
330template <typename IStream> class BitStreamReader {
331private:
332 IStream &m_istream;
333
336 uint8_t m_buffer{0};
337
341 int m_offset{8};
342
343public:
344 explicit BitStreamReader(IStream &istream) : m_istream(istream) {}
345
350 uint64_t Read(int nbits) {
351 if (nbits < 0 || nbits > 64) {
352 throw std::out_of_range("nbits must be between 0 and 64");
353 }
354
355 uint64_t data = 0;
356 while (nbits > 0) {
357 if (m_offset == 8) {
359 m_offset = 0;
360 }
361
362 int bits = std::min(8 - m_offset, nbits);
363 data <<= bits;
364 data |= static_cast<uint8_t>(m_buffer << m_offset) >> (8 - bits);
365 m_offset += bits;
366 nbits -= bits;
367 }
368 return data;
369 }
370};
371
372template <typename OStream> class BitStreamWriter {
373private:
374 OStream &m_ostream;
375
378 uint8_t m_buffer{0};
379
383 int m_offset{0};
384
385public:
386 explicit BitStreamWriter(OStream &ostream) : m_ostream(ostream) {}
387
389
394 void Write(uint64_t data, int nbits) {
395 if (nbits < 0 || nbits > 64) {
396 throw std::out_of_range("nbits must be between 0 and 64");
397 }
398
399 while (nbits > 0) {
400 int bits = std::min(8 - m_offset, nbits);
401 m_buffer |= (data << (64 - nbits)) >> (64 - 8 + m_offset);
402 m_offset += bits;
403 nbits -= bits;
404
405 if (m_offset == 8) {
406 Flush();
407 }
408 }
409 }
410
415 void Flush() {
416 if (m_offset == 0) {
417 return;
418 }
419
421 m_buffer = 0;
422 m_offset = 0;
423 }
424};
425
433class AutoFile {
434protected:
435 std::FILE *m_file;
436
437public:
438 explicit AutoFile(std::FILE *file) : m_file{file} {}
439
441
442 // Disallow copies
443 AutoFile(const AutoFile &) = delete;
444 AutoFile &operator=(const AutoFile &) = delete;
445
446 bool feof() const { return std::feof(m_file); }
447
448 int fclose() {
449 if (auto rel{release()}) {
450 return std::fclose(rel);
451 }
452 return 0;
453 }
454
461 std::FILE *release() {
462 std::FILE *ret{m_file};
463 m_file = nullptr;
464 return ret;
465 }
466
472 std::FILE *Get() const { return m_file; }
473
475 bool IsNull() const { return m_file == nullptr; }
476
478 std::size_t detail_fread(Span<std::byte> dst);
479
480 //
481 // Stream subset
482 //
483 void read(Span<std::byte> dst);
484 void ignore(size_t nSize);
486
487 template <typename T> AutoFile &operator<<(const T &obj) {
488 ::Serialize(*this, obj);
489 return *this;
490 }
491
492 template <typename T> AutoFile &operator>>(T &&obj) {
493 ::Unserialize(*this, obj);
494 return *this;
495 }
496};
497
506private:
509 uint64_t nSrcPos{0};
511 uint64_t m_read_pos{0};
513 uint64_t nReadLimit;
515 uint64_t nRewind;
517 std::vector<std::byte> vchBuf;
518
520 bool Fill() {
521 unsigned int pos = nSrcPos % vchBuf.size();
522 unsigned int readNow = vchBuf.size() - pos;
523 unsigned int nAvail = vchBuf.size() - (nSrcPos - m_read_pos) - nRewind;
524 if (nAvail < readNow) {
525 readNow = nAvail;
526 }
527 if (readNow == 0) {
528 return false;
529 }
530 size_t nBytes{m_src.detail_fread(Span{vchBuf}.subspan(pos, readNow))};
531 if (nBytes == 0) {
532 throw std::ios_base::failure{
533 m_src.feof() ? "BufferedFile::Fill: end of file"
534 : "BufferedFile::Fill: fread failed"};
535 }
536 nSrcPos += nBytes;
537 return true;
538 }
539
545 std::pair<std::byte *, size_t> AdvanceStream(size_t length) {
547 if (m_read_pos + length > nReadLimit) {
548 throw std::ios_base::failure(
549 "Attempt to position past buffer limit");
550 }
551 // If there are no bytes available, read from the file.
552 if (m_read_pos == nSrcPos && length > 0) {
553 Fill();
554 }
555
556 size_t buffer_offset{static_cast<size_t>(m_read_pos % vchBuf.size())};
557 size_t buffer_available{
558 static_cast<size_t>(vchBuf.size() - buffer_offset)};
559 size_t bytes_until_source_pos{
560 static_cast<size_t>(nSrcPos - m_read_pos)};
561 size_t advance{
562 std::min({length, buffer_available, bytes_until_source_pos})};
563 m_read_pos += advance;
564 return std::make_pair(&vchBuf[buffer_offset], advance);
565 }
566
567public:
568 BufferedFile(AutoFile &file, uint64_t nBufSize, uint64_t nRewindIn)
569 : m_src{file}, nReadLimit{std::numeric_limits<uint64_t>::max()},
570 nRewind{nRewindIn}, vchBuf{nBufSize, std::byte{0}} {
571 if (nRewindIn >= nBufSize) {
572 throw std::ios_base::failure(
573 "Rewind limit must be less than buffer size");
574 }
575 }
576
578 bool eof() const { return m_read_pos == nSrcPos && m_src.feof(); }
579
582 while (dst.size() > 0) {
583 auto [buffer_pointer, length]{AdvanceStream(dst.size())};
584 memcpy(dst.data(), buffer_pointer, length);
585 dst = dst.subspan(length);
586 }
587 }
588
591 void SkipTo(const uint64_t file_pos) {
592 assert(file_pos >= m_read_pos);
593 while (m_read_pos < file_pos) {
594 AdvanceStream(file_pos - m_read_pos);
595 }
596 }
597
599 uint64_t GetPos() const { return m_read_pos; }
600
602 bool SetPos(uint64_t nPos) {
603 size_t bufsize = vchBuf.size();
604 if (nPos + bufsize < nSrcPos) {
605 // rewinding too far, rewind as far as possible
606 m_read_pos = nSrcPos - bufsize;
607 return false;
608 }
609 if (nPos > nSrcPos) {
610 // can't go this far forward, go as far as possible
612 return false;
613 }
614 m_read_pos = nPos;
615 return true;
616 }
617
620 bool SetLimit(uint64_t nPos = std::numeric_limits<uint64_t>::max()) {
621 if (nPos < m_read_pos) {
622 return false;
623 }
624 nReadLimit = nPos;
625 return true;
626 }
627
628 template <typename T> BufferedFile &operator>>(T &&obj) {
629 ::Unserialize(*this, obj);
630 return (*this);
631 }
632
634 void FindByte(std::byte byte) {
635 // For best performance, avoid mod operation within the loop.
636 size_t buf_offset{size_t(m_read_pos % uint64_t(vchBuf.size()))};
637 while (true) {
638 if (m_read_pos == nSrcPos) {
639 // No more bytes available; read from the file into the buffer,
640 // setting nSrcPos to one beyond the end of the new data.
641 // Throws exception if end-of-file reached.
642 Fill();
643 }
644 const size_t len{std::min<size_t>(vchBuf.size() - buf_offset,
646 const auto it_start{vchBuf.begin() + buf_offset};
647 const auto it_find{std::find(it_start, it_start + len, byte)};
648 const size_t inc{size_t(std::distance(it_start, it_find))};
649 m_read_pos += inc;
650 if (inc < len) {
651 break;
652 }
653 buf_offset += inc;
654 if (buf_offset >= vchBuf.size()) {
655 buf_offset = 0;
656 }
657 }
658 }
659};
660
661#endif // BITCOIN_STREAMS_H
Non-refcounted RAII wrapper for FILE*.
Definition: streams.h:433
bool feof() const
Definition: streams.h:446
std::FILE * release()
Get wrapped FILE* with transfer of ownership.
Definition: streams.h:461
void ignore(size_t nSize)
Definition: streams.cpp:22
AutoFile & operator=(const AutoFile &)=delete
~AutoFile()
Definition: streams.h:440
std::FILE * m_file
Definition: streams.h:435
void read(Span< std::byte > dst)
Definition: streams.cpp:15
AutoFile & operator<<(const T &obj)
Definition: streams.h:487
AutoFile(const AutoFile &)=delete
bool IsNull() const
Return true if the wrapped FILE* is nullptr, false otherwise.
Definition: streams.h:475
std::FILE * Get() const
Get wrapped FILE* without transfer of ownership.
Definition: streams.h:472
AutoFile & operator>>(T &&obj)
Definition: streams.h:492
std::size_t detail_fread(Span< std::byte > dst)
Implementation detail, only used internally.
Definition: streams.cpp:8
void write(Span< const std::byte > src)
Definition: streams.cpp:39
AutoFile(std::FILE *file)
Definition: streams.h:438
int fclose()
Definition: streams.h:448
uint8_t m_buffer
Buffered byte read in from the input stream.
Definition: streams.h:336
uint64_t Read(int nbits)
Read the specified number of bits from the stream.
Definition: streams.h:350
BitStreamReader(IStream &istream)
Definition: streams.h:344
IStream & m_istream
Definition: streams.h:332
int m_offset
Number of high order bits in m_buffer already returned by previous Read() calls.
Definition: streams.h:341
void Write(uint64_t data, int nbits)
Write the nbits least significant bits of a 64-bit int to the output stream.
Definition: streams.h:394
OStream & m_ostream
Definition: streams.h:374
uint8_t m_buffer
Buffered byte waiting to be written to the output stream.
Definition: streams.h:378
BitStreamWriter(OStream &ostream)
Definition: streams.h:386
int m_offset
Number of high order bits in m_buffer already written by previous Write() calls and not yet flushed t...
Definition: streams.h:383
void Flush()
Flush any unwritten bits to the output stream, padding with 0's to the next byte boundary.
Definition: streams.h:415
Wrapper around an AutoFile& that implements a ring buffer to deserialize from.
Definition: streams.h:505
std::vector< std::byte > vchBuf
the buffer
Definition: streams.h:517
std::pair< std::byte *, size_t > AdvanceStream(size_t length)
Advance the stream's read pointer (m_read_pos) by up to 'length' bytes, filling the buffer from the f...
Definition: streams.h:545
uint64_t nRewind
how many bytes we guarantee to rewind
Definition: streams.h:515
bool eof() const
check whether we're at the end of the source file
Definition: streams.h:578
bool SetLimit(uint64_t nPos=std::numeric_limits< uint64_t >::max())
Prevent reading beyond a certain position.
Definition: streams.h:620
uint64_t m_read_pos
how many bytes have been read from this
Definition: streams.h:511
BufferedFile & operator>>(T &&obj)
Definition: streams.h:628
uint64_t GetPos() const
return the current reading position
Definition: streams.h:599
uint64_t nReadLimit
up to which position we're allowed to read
Definition: streams.h:513
void read(Span< std::byte > dst)
read a number of bytes
Definition: streams.h:581
void SkipTo(const uint64_t file_pos)
Move the read position ahead in the stream to the given position.
Definition: streams.h:591
uint64_t nSrcPos
how many bytes have been read from source
Definition: streams.h:509
void FindByte(std::byte byte)
search for a given byte in the stream, and remain positioned on it
Definition: streams.h:634
BufferedFile(AutoFile &file, uint64_t nBufSize, uint64_t nRewindIn)
Definition: streams.h:568
bool Fill()
read data from the source to fill the buffer
Definition: streams.h:520
AutoFile & m_src
Definition: streams.h:507
bool SetPos(uint64_t nPos)
rewind to a given reading position
Definition: streams.h:602
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:118
void write(Span< const value_type > src)
Definition: streams.h:291
DataStream & operator<<(const T &obj)
Definition: streams.h:296
bool empty() const
Definition: streams.h:152
vector_type::difference_type difference_type
Definition: streams.h:127
size_type size() const
Definition: streams.h:151
DataStream & operator>>(T &&obj)
Definition: streams.h:301
reference operator[](size_type pos)
Definition: streams.h:160
void Xor(const std::vector< uint8_t > &key)
XOR the contents of this stream with a certain key.
Definition: streams.h:311
void resize(size_type n, value_type c=value_type{})
Definition: streams.h:153
void insert(iterator it, const value_type *first, const value_type *last)
Definition: streams.h:187
const_reference operator[](size_type pos) const
Definition: streams.h:157
void insert(iterator it, std::vector< value_type >::const_iterator first, std::vector< value_type >::const_iterator last)
Definition: streams.h:168
DataStream(Span< const value_type > sp)
Definition: streams.h:137
vector_type::size_type size_type
Definition: streams.h:126
iterator erase(iterator it)
Definition: streams.h:203
SerializeData vector_type
Definition: streams.h:120
vector_type vch
Definition: streams.h:121
const value_type * data() const
Definition: streams.h:166
vector_type::const_reference const_reference
Definition: streams.h:129
value_type * data()
Definition: streams.h:165
vector_type::const_iterator const_iterator
Definition: streams.h:132
DataStream(Span< const uint8_t > sp)
Definition: streams.h:136
void reserve(size_type n)
Definition: streams.h:156
vector_type::reverse_iterator reverse_iterator
Definition: streams.h:133
iterator begin()
Definition: streams.h:148
const_iterator begin() const
Definition: streams.h:147
void read(Span< value_type > dst)
Definition: streams.h:258
vector_type::size_type m_read_pos
Definition: streams.h:122
vector_type::iterator iterator
Definition: streams.h:131
vector_type::value_type value_type
Definition: streams.h:130
bool eof() const
Definition: streams.h:255
std::string str() const
Definition: streams.h:140
void ignore(size_t num_ignore)
Definition: streams.h:277
vector_type::allocator_type allocator_type
Definition: streams.h:125
const_iterator end() const
Definition: streams.h:149
void Compact()
Definition: streams.h:233
void clear()
Definition: streams.h:161
iterator end()
Definition: streams.h:150
bool Rewind(std::optional< size_type > n=std::nullopt)
Definition: streams.h:238
DataStream()=default
vector_type::reference reference
Definition: streams.h:128
int in_avail() const
Definition: streams.h:256
iterator erase(iterator first, iterator last)
Definition: streams.h:218
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:94
constexpr std::size_t size() const noexcept
Definition: span.h:210
CONSTEXPR_IF_NOT_DEBUG Span< C > subspan(std::size_t offset) const noexcept
Definition: span.h:219
constexpr C * data() const noexcept
Definition: span.h:199
constexpr C * begin() const noexcept
Definition: span.h:200
constexpr bool empty() const noexcept
Definition: span.h:214
constexpr C * end() const noexcept
Definition: span.h:201
Minimal stream for reading from an existing byte array by Span.
Definition: streams.h:79
bool empty() const
Definition: streams.h:95
size_t size() const
Definition: streams.h:94
Span< const uint8_t > m_data
Definition: streams.h:81
SpanReader(Span< const uint8_t > data)
Definition: streams.h:87
SpanReader & operator>>(T &obj)
Definition: streams.h:89
void read(Span< std::byte > dst)
Definition: streams.h:97
Minimal stream for overwriting and/or appending to an existing byte vector.
Definition: streams.h:31
VectorWriter(std::vector< uint8_t > &vchDataIn, size_t nPosIn, Args &&...args)
(other params same as above)
Definition: streams.h:50
VectorWriter & operator<<(const T &obj)
Definition: streams.h:66
size_t nPos
Definition: streams.h:73
void write(Span< const std::byte > src)
Definition: streams.h:54
VectorWriter(std::vector< uint8_t > &vchDataIn, size_t nPosIn)
Definition: streams.h:39
std::vector< uint8_t > & vchData
Definition: streams.h:72
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:259
std::optional< T > CheckedAdd(const T i, const T j) noexcept
Definition: overflow.h:23
void Serialize(Stream &, V)=delete
void Unserialize(Stream &, V)=delete
void SerializeMany(Stream &s, const Args &...args)
Definition: serialize.h:1217
uint8_t * UCharCast(char *c)
Definition: span.h:310
Span< const std::byte > AsBytes(Span< T > s) noexcept
Definition: span.h:295
assert(!tx.IsCoinBase())
std::vector< std::byte, zero_after_free_allocator< std::byte > > SerializeData
Byte-vector that clears its contents before deletion.
Definition: zeroafterfree.h:44