Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 37 additions & 28 deletions include/bitcoin/database/impl/query/archive/wire_writer.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,26 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction_view& tx,
return error::tx_tx_set;
}

auto ins = tx.get_inputs_stream();
read::bytes::fast isource{ ins };

// Commit points (hashmap).
if (coinbase)
{
// Should only be one input, but generalized anyway.
if (!store_.point.expand(ins_fk + inputs))
return error::tx_point_allocate;

auto source = tx.get_inputs_stream();
read::bytes::fast ins{ source };
for (size_t in{}; in < inputs; ++in)
{
// Should always be a null point - but could be invalid.
if (!store_.point.put(ins_fk++, chain::point(ins),
if (!store_.point.put(ins_fk++, chain::point(isource),
table::point::record{}))
return error::tx_null_point_put;

// Skip script.
ins.skip_bytes(ins.read_size());
// Skip script and sequence.
isource.skip_bytes(isource.read_size());
isource.skip_bytes(sizeof(uint32_t));
}
}
else
Expand All @@ -118,23 +120,23 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction_view& tx,
// Collect duplicates to store in duplicate table.
std::vector<chain::point> twins{};
auto ptr = store_.point.get_memory();
auto source = tx.get_inputs_stream();
read::bytes::fast ins{ source };

for (size_t in{}; in < inputs; ++in)
{
bool duplicate{};
if (!store_.point.put(duplicate, ptr, ins_fk++,
chain::point(ins), table::point::record{}))
chain::point(isource), table::point::record{}))
return error::tx_point_put;

if (duplicate)
{
ins.rewind_bytes(chain::point::serialized_size());
twins.push_back(chain::point(ins));
isource.rewind_bytes(chain::point::serialized_size());
twins.push_back(chain::point(isource));
}

// Skip script.
ins.skip_bytes(ins.read_size());
// Skip script and sequence.
isource.skip_bytes(isource.read_size());
isource.skip_bytes(sizeof(uint32_t));
}

ptr.reset();
Expand All @@ -149,48 +151,55 @@ code CLASS::set_code(const tx_link& tx_fk, const transaction_view& tx,
else
{
auto ptr = store_.point.get_memory();
auto source = tx.get_inputs_stream();
read::bytes::fast ins{ source };

for (size_t in{}; in < inputs; ++in)
{
if (!store_.point.put(ptr, ins_fk++, chain::point(ins),
if (!store_.point.put(ptr, ins_fk++, chain::point(isource),
table::point::record{}))
return error::tx_point_put;

// Skip script.
ins.skip_bytes(ins.read_size());
// Skip script and sequence.
isource.skip_bytes(isource.read_size());
isource.skip_bytes(sizeof(uint32_t));
}

ptr.reset();
}
}

BC_ASSERT(isource);
if (!isource)
return error::tx_null_point_put;

// Commit address index records (hashmap).
if (address_enabled())
{
auto ad_fk = store_.address.allocate(outputs);
if (ad_fk.is_terminal())
return error::tx_address_allocate;

constexpr auto value_parent = sizeof(uint64_t) - tx_link::size;
const auto ptr = store_.address.get_memory();
auto source = tx.get_outputs_stream();
read::bytes::fast ous{ source };
auto outs = tx.get_outputs_stream();
read::bytes::fast osource{ outs };

for (size_t out{}; out < outputs; ++out)
{
const auto start = ous.get_read_position();
const auto value = ous.read_variable();
const auto value = osource.read_8_bytes_little_endian();
const auto bytes = osource.read_size();

if (!store_.address.put(ptr, ad_fk++,
sha256_hash(ous.read_bytes(ous.read_size())),
sha256_hash(osource.read_bytes(bytes)),
table::address::record{ {}, out_fk }))
return error::tx_address_put;

// See outs::put_ref.
// Calculate next corresponding output fk from serialized size.
// (variable_size(value) + (value + script)) - (value - parent)
const auto output_size = ous.get_read_position() - start;
out_fk.value += (variable_size(value) + output_size - value_parent);
out_fk.value += possible_narrow_cast<output_link::integer>(
tx_link::size + variable_size(value) + variable_size(bytes) +
bytes);
}

BC_ASSERT(osource);
if (!osource)
return error::tx_address_put;
}

// Commit tx to search (hashmap).
Expand Down
68 changes: 24 additions & 44 deletions include/bitcoin/database/tables/archives/input.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,65 +182,45 @@ struct input
inline link count() const NOEXCEPT
{
using namespace system;
constexpr auto sequence_size = sizeof(uint32_t);
constexpr auto sequence_point_size = sequence_size +
chain::point::serialized_size();

size_t total{};
return possible_narrow_cast<link::integer>(tx_.input_table_size());
}

inline bool to_data(flipper& sink) const NOEXCEPT
{
using namespace system;
auto istream = tx_.get_inputs_stream();
read::bytes::fast isource{ istream };
for (size_t in{}; in < tx_.inputs(); ++in)
{
const auto start = isource.get_read_position();
isource.skip_bytes(chain::point::serialized_size());
isource.skip_bytes(isource.read_size() + sequence_size);
const auto input_size = isource.get_read_position() - start;
total += (input_size - sequence_point_size);
}

if (!tx_.is_segregated())
{
// Optimize out stream and loop for non-segregated.
total += (tx_.inputs() * variable_size(zero));
}
else
if (tx_.is_segregated())
{
auto wstream = tx_.get_witnesses_stream();
read::bytes::fast wsource{ wstream };

for (size_t in{}; in < tx_.inputs(); ++in)
{
const auto stack = wsource.read_size();
total += variable_size(stack);
for (size_t element{}; element < stack; ++element)
{
const auto element_size = wsource.read_size();
wsource.skip_bytes(element_size);
total += variable_size(element_size) + element_size;
}
// input script + witness stack
tx_.write_input_script(sink, isource);
isource.skip_bytes(sizeof(uint32_t));
tx_.write_witness(sink, wsource);
}
}

return possible_narrow_cast<link::integer>(total);
}

inline bool to_data(flipper& sink) const NOEXCEPT
{
using namespace system;
auto istream = tx_.get_inputs_stream();
auto wstream = tx_.get_witnesses_stream();
read::bytes::fast isource{ istream };
read::bytes::fast wsource{ wstream };
for (size_t in{}; in < tx_.inputs(); ++in)
if (!wsource)
isource.invalidate();
}
else
{
// input (without point) + witness stack (or zero).
tx_.write_input_script(sink, isource);
tx_.write_witness(sink, wsource);
for (size_t in{}; in < tx_.inputs(); ++in)
{
// input script + empty witness stack
tx_.write_input_script(sink, isource);
isource.skip_bytes(sizeof(uint32_t));
sink.write_variable(zero);
}
}

BC_ASSERT(isource && wsource);
BC_ASSERT(isource);
BC_ASSERT(!sink || sink.get_write_position() == count());
return sink && isource && wsource;
return sink && isource;
}

const system::chain::transaction_view& tx_;
Expand Down
49 changes: 37 additions & 12 deletions include/bitcoin/database/tables/archives/ins.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,22 +144,47 @@ struct ins
inline bool to_data(flipper& sink) const NOEXCEPT
{
using namespace system;
constexpr auto sequence_point_size = sizeof(uint32_t) +
chain::point::serialized_size();

auto in_fk = input_fk;
auto stream = tx_.get_inputs_stream();
read::bytes::fast source{ stream };
for (size_t in{}; in < tx_.inputs(); ++in)

if (tx_.is_segregated())
{
const auto start = source.get_read_position();
source.skip_bytes(chain::point::serialized_size());
source.skip_bytes(source.read_size());
sink.write_little_endian(source.read_little_endian<uint32_t>());
sink.write_little_endian<in::integer, in::size>(in_fk);
sink.write_little_endian<tx::integer, tx::size>(parent_fk);
const auto input_size = source.get_read_position() - start;
in_fk += (input_size - sequence_point_size);
auto wstream = tx_.get_witnesses_stream();
read::bytes::fast wsource{ wstream };

for (size_t in{}; in < tx_.inputs(); ++in)
{
source.skip_bytes(chain::point::serialized_size());
const auto bytes = source.read_size();
source.skip_bytes(bytes);
const auto sequence = source.read_little_endian<uint32_t>();

sink.write_little_endian<uint32_t>(sequence);
sink.write_little_endian<in::integer, in::size>(in_fk);
sink.write_little_endian<tx::integer, tx::size>(parent_fk);

// Advance by size stored in input table for this input.
in_fk += variable_size(bytes) + bytes +
tx_.read_witness_size(wsource);
}
}
else
{
for (size_t in{}; in < tx_.inputs(); ++in)
{
source.skip_bytes(chain::point::serialized_size());
const auto bytes = source.read_size();
source.skip_bytes(bytes);
const auto sequence = source.read_little_endian<uint32_t>();

sink.write_little_endian<uint32_t>(sequence);
sink.write_little_endian<in::integer, in::size>(in_fk);
sink.write_little_endian<tx::integer, tx::size>(parent_fk);

// Advance by size stored in input table for this input.
in_fk += variable_size(bytes) + bytes + variable_size(zero);
}
}

BC_ASSERT(source);
Expand Down
30 changes: 8 additions & 22 deletions include/bitcoin/database/tables/archives/output.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,42 +236,28 @@ struct output
inline link count() const NOEXCEPT
{
using namespace system;
static_assert(tx::size <= sizeof(uint64_t));
constexpr auto value_size = sizeof(uint64_t);
constexpr auto value_parent = value_size - tx::size;

size_t outputs{};
const auto other = tx_.outputs() * value_parent;

auto stream = tx_.get_outputs_stream();
read::bytes::fast source{ stream };
for (size_t out{}; out < tx_.outputs(); ++out)
{
const auto start = source.get_read_position();
const auto value = source.read_8_bytes_little_endian();
source.skip_bytes(source.read_size());
const auto output_size = source.get_read_position() - start;
outputs += variable_size(value) + output_size;
}

// Converts value from fixed size wire encoding to variable.
// (variable_size(value) + (value + script)) - (value - parent)
return possible_narrow_cast<link::integer>(outputs - other);
const auto parents_size = tx_.outputs() * tx::size;
return possible_narrow_cast<link::integer>(parents_size +
tx_.output_table_size());
}

inline bool to_data(flipper& sink) const NOEXCEPT
{
using namespace system;
auto stream = tx_.get_outputs_stream();
read::bytes::fast source{ stream };

for (size_t out{}; out < tx_.outputs(); ++out)
{
// tx view output writer not used due to variable value.
sink.write_little_endian<tx::integer, tx::size>(parent_fk);
sink.write_variable(source.read_8_bytes_little_endian());
sink.write_bytes(source.read_bytes(source.read_size()));
const auto bytes = source.read_size();
sink.write_variable(bytes);
sink.write_bytes(source.read_bytes(bytes));
}

BC_ASSERT(source);
BC_ASSERT(!sink || sink.get_write_position() == count());
return sink;
}
Expand Down
14 changes: 5 additions & 9 deletions include/bitcoin/database/tables/archives/outs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,21 +141,17 @@ struct outs
inline bool to_data(flipper& sink) const NOEXCEPT
{
using namespace system;
static_assert(tx::size <= sizeof(uint64_t));
constexpr auto value_parent = sizeof(uint64_t) - tx::size;

auto out_fk = output_fk;
auto stream = tx_.get_outputs_stream();
read::bytes::fast source{ stream };
for (size_t out{}; out < tx_.outputs(); ++out)
{
sink.write_little_endian<out::integer, out::size>(out_fk);

const auto start = source.get_read_position();
const auto value = source.read_variable();
source.skip_bytes(source.read_size());
const auto output_size = source.get_read_position() - start;
out_fk += (variable_size(value) + output_size - value_parent);
const auto value = source.read_8_bytes_little_endian();
const auto bytes = source.read_size();
source.skip_bytes(bytes);
out_fk += tx::size + variable_size(value)
+ variable_size(bytes) + bytes;
}

BC_ASSERT(source);
Expand Down
1 change: 0 additions & 1 deletion include/bitcoin/database/tables/archives/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ struct transaction
{
using namespace system;

// is_coinbase() is computed over the point.
const auto coinbase = tx.is_coinbase();
const auto light_ = tx.serialized_size(false);
const auto heavy_ = tx.serialized_size(true);
Expand Down
Loading