Skip to content

Commit 4bf2133

Browse files
authored
Merge pull request #1606 from evoskuil/master
Fix size cache for size(true) when tx is not segregated.
2 parents 82de754 + 91c3ff7 commit 4bf2133

File tree

7 files changed

+69
-66
lines changed

7 files changed

+69
-66
lines changed

include/bitcoin/system/chain/block.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ class BC_API block
193193

194194
void assign_data(reader& source, bool witness) NOEXCEPT;
195195
static block from_data(reader& source, bool witness) NOEXCEPT;
196-
static sizes serialized_size(const chain::transaction_cptrs& txs) NOEXCEPT;
196+
static sizes serialized_size(const transaction_cptrs& txs) NOEXCEPT;
197197

198198
// context free
199199
hash_digest generate_merkle_root(bool witness) const NOEXCEPT;

include/bitcoin/system/chain/transaction.hpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ class BC_API transaction
9292

9393
/// Native properties.
9494
bool is_valid() const NOEXCEPT;
95+
size_t spends() const NOEXCEPT;
9596
size_t inputs() const NOEXCEPT;
9697
size_t outputs() const NOEXCEPT;
9798
uint32_t version() const NOEXCEPT;
@@ -166,8 +167,8 @@ class BC_API transaction
166167
code confirm(const context& ctx) const NOEXCEPT;
167168

168169
protected:
169-
transaction(uint32_t version, const chain::inputs_cptr& inputs,
170-
const chain::outputs_cptr& outputs, uint32_t locktime, bool segregated,
170+
transaction(uint32_t version, const inputs_cptr& inputs,
171+
const outputs_cptr& outputs, uint32_t locktime, bool segregated,
171172
bool valid) NOEXCEPT;
172173

173174
/// Guard (context free).
@@ -236,9 +237,9 @@ class BC_API transaction
236237
} sighash_cache;
237238

238239
static bool segregated(const chain::inputs& inputs) NOEXCEPT;
239-
static bool segregated(const chain::input_cptrs& inputs) NOEXCEPT;
240-
static sizes serialized_size(const chain::input_cptrs& inputs,
241-
const chain::output_cptrs& outputs, bool segregated) NOEXCEPT;
240+
static bool segregated(const input_cptrs& inputs) NOEXCEPT;
241+
static sizes serialized_size(const input_cptrs& inputs,
242+
const output_cptrs& outputs, bool segregated) NOEXCEPT;
242243

243244
void assign_data(reader& source, bool witness) NOEXCEPT;
244245

include/bitcoin/system/chain/witness.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ class BC_API witness
9090
const chunk_cptrs& stack() const NOEXCEPT;
9191

9292
/// Computed properties.
93+
/// serialized_size(true) returns one for an empty witness stack.
9394
size_t serialized_size(bool prefix) const NOEXCEPT;
9495

9596
/// Utilities.

src/chain/block.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,7 @@ void block::set_hashes(const data_chunk& data) NOEXCEPT
332332
}
333333

334334
// static/private
335-
block::sizes block::serialized_size(
336-
const chain::transaction_cptrs& txs) NOEXCEPT
335+
block::sizes block::serialized_size(const transaction_cptrs& txs) NOEXCEPT
337336
{
338337
sizes size{};
339338
std::for_each(txs.begin(), txs.end(), [&](const auto& tx) NOEXCEPT
@@ -342,11 +341,11 @@ block::sizes block::serialized_size(
342341
size.witnessed = ceilinged_add(size.witnessed, tx->serialized_size(true));
343342
});
344343

345-
const auto common_size = ceilinged_add(header::serialized_size(),
344+
const auto base_size = ceilinged_add(header::serialized_size(),
346345
variable_size(txs.size()));
347346

348-
const auto nominal_size = ceilinged_add(common_size, size.nominal);
349-
const auto witnessed_size = ceilinged_add(common_size, size.witnessed);
347+
const auto nominal_size = ceilinged_add(base_size, size.nominal);
348+
const auto witnessed_size = ceilinged_add(base_size, size.witnessed);
350349

351350
return { nominal_size, witnessed_size };
352351
}

src/chain/input.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,14 @@ input::sizes input::serialized_size(const chain::script& script,
284284
const auto nominal_size = ceilinged_add(const_size,
285285
script.serialized_size(true));
286286

287+
// The input has no way to determine if its tx is segregated, as an empty
288+
// witness applies to segregated tx as a one byte (zero) serialization.
289+
// This determination is therefore left to the transaction, and witness
290+
// retains both serialization options from construction.
287291
const auto witnessed_size = ceilinged_add(nominal_size,
288292
witness.serialized_size(true));
289293

294+
// Values are the same for non-segregated transactions.
290295
return { nominal_size, witnessed_size };
291296
}
292297

src/chain/transaction.cpp

+19-28
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ transaction::transaction(uint32_t version, const chain::inputs& inputs,
9292
{
9393
}
9494

95-
transaction::transaction(uint32_t version, const chain::inputs_cptr& inputs,
96-
const chain::outputs_cptr& outputs, uint32_t locktime) NOEXCEPT
95+
transaction::transaction(uint32_t version, const inputs_cptr& inputs,
96+
const outputs_cptr& outputs, uint32_t locktime) NOEXCEPT
9797
: transaction(version, inputs, outputs, locktime, segregated(*inputs), true)
9898
{
9999
}
@@ -284,31 +284,17 @@ void transaction::to_data(writer& sink, bool witness) const NOEXCEPT
284284
}
285285

286286
// static/private
287-
transaction::sizes transaction::serialized_size(
288-
const chain::input_cptrs& inputs,
289-
const chain::output_cptrs& outputs, bool segregated) NOEXCEPT
287+
transaction::sizes transaction::serialized_size(const input_cptrs& inputs,
288+
const output_cptrs& outputs, bool segregated) NOEXCEPT
290289
{
291290
sizes size{ zero, zero };
292291

293-
// Keep the condition outside of the loop.
294-
if (segregated)
292+
std::for_each(inputs.begin(), inputs.end(), [&](const auto& in) NOEXCEPT
295293
{
296-
std::for_each(inputs.begin(), inputs.end(), [&](const auto& in) NOEXCEPT
297-
{
298-
size.nominal = ceilinged_add(size.nominal, in->nominal_size());
294+
size.nominal = ceilinged_add(size.nominal, in->nominal_size());
295+
if (segregated)
299296
size.witnessed = ceilinged_add(size.witnessed, in->witnessed_size());
300-
});
301-
}
302-
else
303-
{
304-
// Witness must be zeroed because witnesses have nonzero size when they
305-
// are zero-valued, so they can be archived easily. Also it would be
306-
// wasteful to to count mutiple zero sizes, so exclude them here.
307-
std::for_each(inputs.begin(), inputs.end(), [&](const auto& in) NOEXCEPT
308-
{
309-
size.nominal = ceilinged_add(size.nominal, in->nominal_size());
310-
});
311-
}
297+
});
312298

313299
const auto outs = [](size_t total, const auto& output) NOEXCEPT
314300
{
@@ -317,20 +303,20 @@ transaction::sizes transaction::serialized_size(
317303

318304
constexpr auto base_const_size = ceilinged_add(sizeof(version_),
319305
sizeof(locktime_));
320-
321306
constexpr auto witness_const_size = ceilinged_add(sizeof(witness_marker),
322307
sizeof(witness_enabled));
323308

324309
const auto base_size = ceilinged_add(ceilinged_add(ceilinged_add(
325310
base_const_size, variable_size(inputs.size())),
326311
variable_size(outputs.size())),
327312
std::accumulate(outputs.begin(), outputs.end(), zero, outs));
328-
329313
const auto nominal_size = ceilinged_add(base_size, size.nominal);
330-
const auto witnessed_size = ceilinged_add(ceilinged_add(base_size,
331-
witness_const_size),
332-
size.witnessed);
333314

315+
// witnessed_size is nominal_size for non-segregated transactions.
316+
const auto witnessed_size = segregated ? ceilinged_add(ceilinged_add(
317+
base_size, witness_const_size), size.witnessed) : nominal_size;
318+
319+
// Values are the same for non-segregated transactions.
334320
return { nominal_size, witnessed_size };
335321
}
336322

@@ -349,6 +335,11 @@ bool transaction::is_valid() const NOEXCEPT
349335
return valid_;
350336
}
351337

338+
size_t transaction::spends() const NOEXCEPT
339+
{
340+
return is_coinbase() ? zero : inputs_->size();
341+
}
342+
352343
size_t transaction::inputs() const NOEXCEPT
353344
{
354345
return inputs_->size();
@@ -983,7 +974,7 @@ bool transaction::segregated(const chain::inputs& inputs) NOEXCEPT
983974
}
984975

985976
// static/private
986-
bool transaction::segregated(const chain::input_cptrs& inputs) NOEXCEPT
977+
bool transaction::segregated(const input_cptrs& inputs) NOEXCEPT
987978
{
988979
const auto witnessed = [](const auto& input) NOEXCEPT
989980
{

test/config/block.cpp

+33-27
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,15 @@ static const std::string encoded_genesis_block =
4545
"4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac"
4646
"00000000";
4747

48+
static const config::block genesis_config()
49+
{
50+
return { encoded_genesis_block };
51+
};
4852

49-
static const config::block genesis_config{ encoded_genesis_block };
50-
static const chain::block genesis_chain{ genesis_config };
53+
static const chain::block genesis_chain()
54+
{
55+
return { genesis_config() };
56+
};
5157

5258
BOOST_AUTO_TEST_CASE(block__construct__default)
5359
{
@@ -57,28 +63,28 @@ BOOST_AUTO_TEST_CASE(block__construct__default)
5763

5864
BOOST_AUTO_TEST_CASE(block__construct__copy__expected)
5965
{
60-
const block block(genesis_config);
61-
BOOST_REQUIRE_EQUAL(block, genesis_config);
66+
const block block(genesis_config());
67+
BOOST_REQUIRE_EQUAL(block, genesis_config());
6268
}
6369

6470
BOOST_AUTO_TEST_CASE(block__construct__move__expected)
6571
{
66-
auto genesis = genesis_config;
72+
auto genesis = genesis_config();
6773
const block block(std::move(genesis));
68-
BOOST_REQUIRE_EQUAL(block, genesis_config);
74+
BOOST_REQUIRE_EQUAL(block, genesis_config());
6975
}
7076

7177
BOOST_AUTO_TEST_CASE(block__construct__chain_copy__expected)
7278
{
73-
const block block(genesis_chain);
74-
BOOST_REQUIRE_EQUAL(block, genesis_config);
79+
const block block(genesis_chain());
80+
BOOST_REQUIRE_EQUAL(block, genesis_config());
7581
}
7682

7783
BOOST_AUTO_TEST_CASE(block__construct__chain_move__expected)
7884
{
79-
chain::block genesis = genesis_config;
85+
chain::block genesis = genesis_config();
8086
const block block(std::move(genesis));
81-
BOOST_REQUIRE_EQUAL(block, genesis_config);
87+
BOOST_REQUIRE_EQUAL(block, genesis_config());
8288
}
8389

8490
BOOST_AUTO_TEST_CASE(block__construct__string__expected)
@@ -90,61 +96,61 @@ BOOST_AUTO_TEST_CASE(block__construct__string__expected)
9096
BOOST_AUTO_TEST_CASE(block__assign__copy__expected)
9197
{
9298
block block{};
93-
block = genesis_config;
94-
BOOST_REQUIRE_EQUAL(block, genesis_config);
99+
block = genesis_config();
100+
BOOST_REQUIRE_EQUAL(block, genesis_config());
95101
}
96102

97103
BOOST_AUTO_TEST_CASE(block__assign__move__expected)
98104
{
99-
auto genesis = genesis_config;
105+
auto genesis = genesis_config();
100106
block block{};
101107
block = std::move(genesis);
102-
BOOST_REQUIRE_EQUAL(block, genesis_config);
108+
BOOST_REQUIRE_EQUAL(block, genesis_config());
103109
}
104110

105111
BOOST_AUTO_TEST_CASE(block__assign__chain_copy__expected)
106112
{
107113
block block{};
108-
block = genesis_chain;
109-
BOOST_REQUIRE_EQUAL(block, genesis_config);
114+
block = genesis_chain();
115+
BOOST_REQUIRE_EQUAL(block, genesis_config());
110116
}
111117

112118
BOOST_AUTO_TEST_CASE(block__assign__chain_move__expected)
113119
{
114-
auto genesis = genesis_chain;
120+
auto genesis = genesis_chain();
115121
block block{};
116122
block = std::move(genesis);
117-
BOOST_REQUIRE_EQUAL(block, genesis_config);
123+
BOOST_REQUIRE_EQUAL(block, genesis_config());
118124
}
119125

120126
BOOST_AUTO_TEST_CASE(block__equality__equal__true)
121127
{
122-
const block block{ genesis_config };
123-
BOOST_REQUIRE(block == genesis_config);
128+
const block block{ genesis_config() };
129+
BOOST_REQUIRE(block == genesis_config());
124130
}
125131

126132
BOOST_AUTO_TEST_CASE(block__equality__not_equal__false)
127133
{
128134
const block block{};
129-
BOOST_REQUIRE(!(block == genesis_config));
135+
BOOST_REQUIRE(!(block == genesis_config()));
130136
}
131137

132138
BOOST_AUTO_TEST_CASE(block__inequality__equal__false)
133139
{
134-
const block block{ genesis_config };
135-
BOOST_REQUIRE(!(block != genesis_config));
140+
const block block{ genesis_config() };
141+
BOOST_REQUIRE(!(block != genesis_config()));
136142
}
137143

138144
BOOST_AUTO_TEST_CASE(block__inequality__not_equal__true)
139145
{
140146
const block block{};
141-
BOOST_REQUIRE(block != genesis_config);
147+
BOOST_REQUIRE(block != genesis_config());
142148
}
143149

144150
BOOST_AUTO_TEST_CASE(block__equality__chain__expected)
145151
{
146152
const block block{};
147-
BOOST_REQUIRE(block != genesis_chain);
153+
BOOST_REQUIRE(block != genesis_chain());
148154
}
149155

150156
BOOST_AUTO_TEST_CASE(block__istream__populated__expected)
@@ -165,13 +171,13 @@ BOOST_AUTO_TEST_CASE(block__ostream__empty__expected)
165171
BOOST_AUTO_TEST_CASE(block__ostream__populated__expected)
166172
{
167173
std::stringstream serialized;
168-
serialized << genesis_config;
174+
serialized << genesis_config();
169175
BOOST_REQUIRE_EQUAL(serialized.str(), encoded_genesis_block);
170176
}
171177

172178
BOOST_AUTO_TEST_CASE(block__ostream__boost_lexical_cast__expected)
173179
{
174-
const auto serialized = boost::lexical_cast<std::string>(genesis_config);
180+
const auto serialized = boost::lexical_cast<std::string>(genesis_config());
175181
BOOST_REQUIRE_EQUAL(serialized, encoded_genesis_block);
176182
}
177183

0 commit comments

Comments
 (0)