@@ -28,6 +28,9 @@ namespace database {
2828
2929// Wire serialized objects.
3030// ----------------------------------------------------------------------------
31+ // Due to the idiotic segwit serialization of witness after output there is are
32+ // duplicated navigations to store_.ins and store_.input by the witness reader.
33+ // This normalized approach is also the most efficient.
3134
3235TEMPLATE
3336bool CLASS::get_wire_header (byteflipper& flipper,
@@ -41,60 +44,207 @@ bool CLASS::get_wire_header(byteflipper& flipper,
4144 return false ;
4245 }
4346
44- // Genesis header parent is defaulted, others must be looked up.
45- if (header.parent_fk != schema::header::link::terminal)
47+ // Genesis header parent is defaulted.
48+ if (header.parent_fk == schema::header::link::terminal)
49+ return true ;
50+
51+ flipper.set_position (start);
52+ table::header::wire_key key{ {}, flipper };
53+ if (!store_.header .get (header.parent_fk , key))
4654 {
47- flipper.set_position (start);
48- table::header::wire_key key{ {}, flipper };
49- if (!store_.header .get (header.parent_fk , key))
50- {
51- flipper.invalidate ();
52- return false ;
53- }
54-
55- flipper.set_position (start + system::chain::header::serialized_size ());
55+ flipper.invalidate ();
56+ return false ;
57+ }
58+
59+ return true ;
60+ }
61+
62+ TEMPLATE
63+ bool CLASS::get_wire_input (byteflipper& flipper,
64+ const point_link& link) const NOEXCEPT
65+ {
66+ // [point]
67+ table::point::wire_point point{ {}, flipper };
68+ if (!store_.point .get (link, point))
69+ {
70+ flipper.invalidate ();
71+ return false ;
5672 }
5773
74+ // [[size]script]
75+ table::ins::get_input ins{};
76+ table::input::wire_script script{ {}, flipper };
77+ if (!store_.ins .get (link, ins) ||
78+ !store_.input .get (ins.input_fk , script))
79+ {
80+ flipper.invalidate ();
81+ return false ;
82+ }
83+
84+ // [sequence]
85+ flipper.write_4_bytes_little_endian (ins.sequence );
5886 return true ;
5987}
6088
6189TEMPLATE
62- bool CLASS::get_wire_tx (byteflipper& , const tx_link& ,
63- bool ) const NOEXCEPT
90+ bool CLASS::get_wire_output (byteflipper& flipper ,
91+ const output_link& link ) const NOEXCEPT
6492{
65- return {};
93+ // [value][[[size]script]]
94+ table::output::wire_script out{ {}, flipper };
95+ if (!store_.output .get (link, out))
96+ {
97+ flipper.invalidate ();
98+ return false ;
99+ }
100+
101+ return true ;
102+ }
103+
104+ TEMPLATE
105+ bool CLASS::get_wire_witness (byteflipper& flipper,
106+ const point_link& link) const NOEXCEPT
107+ {
108+ // [count][[[size]element]]
109+ table::ins::get_input ins{};
110+ table::input::wire_witness wire{ {}, flipper };
111+ if (!store_.ins .get (link, ins) ||
112+ !store_.input .get (ins.input_fk , wire))
113+ {
114+ flipper.invalidate ();
115+ return false ;
116+ }
117+
118+ return true ;
119+ }
120+
121+ TEMPLATE
122+ bool CLASS::get_wire_tx (byteflipper& flipper, const tx_link& link,
123+ bool witness) const NOEXCEPT
124+ {
125+ table::transaction::record tx{};
126+ if (!store_.tx .get (link, tx))
127+ {
128+ flipper.invalidate ();
129+ return false ;
130+ }
131+
132+ table::outs::record outs{};
133+ outs.out_fks .resize (tx.outs_count );
134+ if (!store_.outs .get (tx.outs_fk , outs))
135+ {
136+ flipper.invalidate ();
137+ return false ;
138+ }
139+
140+ // Point links are contiguous (computed).
141+ const auto ins_begin = tx.point_fk ;
142+ const auto ins_count = tx.ins_count ;
143+ const auto ins_final = ins_begin + ins_count;
144+ const auto witnessed = witness && (tx.heavy != tx.light );
145+
146+ flipper.write_4_bytes_little_endian (tx.version );
147+
148+ if (witnessed)
149+ {
150+ flipper.write_byte (system::chain::witness_marker);
151+ flipper.write_byte (system::chain::witness_enabled);
152+ }
153+
154+ flipper.write_variable (ins_count);
155+ for (auto fk = ins_begin; fk < ins_final; ++fk)
156+ if (!get_wire_input (flipper, fk))
157+ return false ;
158+
159+ flipper.write_variable (outs.out_fks .size ());
160+ for (const auto & fk: outs.out_fks )
161+ if (!get_wire_output (flipper, fk))
162+ return false ;
163+
164+ if (witnessed)
165+ {
166+ for (auto fk = ins_begin; fk < ins_final; ++fk)
167+ if (!get_wire_witness (flipper, fk))
168+ return false ;
169+ }
170+
171+ flipper.write_4_bytes_little_endian (tx.locktime );
172+ return true ;
66173}
67174
68175TEMPLATE
69- bool CLASS::get_wire_block (byteflipper& , const header_link& ,
70- bool ) const NOEXCEPT
176+ bool CLASS::get_wire_block (byteflipper& flipper , const header_link& link ,
177+ bool witness ) const NOEXCEPT
71178{
72- return {};
179+ if (!get_wire_header (flipper, link))
180+ return false ;
181+
182+ const auto txs = to_transactions (link);
183+ if (txs.empty ())
184+ {
185+ flipper.invalidate ();
186+ return false ;
187+ }
188+
189+ flipper.write_variable (txs.size ());
190+ for (const auto & tx_link: txs)
191+ if (!get_wire_tx (flipper, tx_link, witness))
192+ return false ;
193+
194+ return true ;
73195}
74196
197+ // These convenience wrappers are made practical by size caching for block and
198+ // tx for both nominal and witness wire encodings (and fixed size headers).
199+ // Intermediate objects (input, output, witness) have a size prefix
200+
75201TEMPLATE
76202data_chunk CLASS::get_wire_header (const header_link& link) const NOEXCEPT
77203{
78204 using namespace system ;
79205 data_chunk data (chain::header::serialized_size ());
206+
80207 stream::flip::fast ostream (data);
81208 flip::bytes::fast out (ostream);
82209 if (!get_wire_header (out, link) || !out)
83- data. clear () ;
210+ return {} ;
84211
85212 return data;
86213}
87214
88215TEMPLATE
89- data_chunk CLASS::get_wire_tx (const tx_link& , bool ) const NOEXCEPT
216+ data_chunk CLASS::get_wire_tx (const tx_link& link , bool witness ) const NOEXCEPT
90217{
91- return {};
218+ using namespace system ;
219+ size_t size{};
220+ if (!get_tx_size (size, link, witness))
221+ return {};
222+
223+ data_chunk data (size);
224+ stream::flip::fast ostream (data);
225+ flip::bytes::fast out (ostream);
226+ if (!get_wire_tx (out, link, witness) || !out)
227+ return {};
228+
229+ return data;
92230}
93231
94232TEMPLATE
95- data_chunk CLASS::get_wire_block (const header_link& , bool ) const NOEXCEPT
233+ data_chunk CLASS::get_wire_block (const header_link& link,
234+ bool witness) const NOEXCEPT
96235{
97- return {};
236+ using namespace system ;
237+ size_t size{};
238+ if (!get_block_size (size, link, witness))
239+ return {};
240+
241+ data_chunk data (size);
242+ stream::flip::fast ostream (data);
243+ flip::bytes::fast out (ostream);
244+ if (!get_wire_block (out, link, witness) || !out)
245+ return {};
246+
247+ return data;
98248}
99249
100250} // namespace database
0 commit comments