View in context in the libbitcoin Slack #general mirror.
void executor::read_test() const
{
constexpr auto start_tx = 15'000_u32;
constexpr auto ns_to_ms = 1'000'000_i64;
constexpr auto target_count = 3000_size;
// Set ensures unique addresses.
std::set<hash_digest> keys{};
auto tx = start_tx;
console(format("Getting first [%1%] output address hashes.") %
target_count);
auto start = fine_clock::now();
while (!cancel_ && keys.size() < target_count)
{
const auto outputs = query_.get_outputs(tx++);
if (outputs->empty())
return;
for (const auto& put: *outputs)
{
keys.emplace(put->script().hash());
if (cancel_ || keys.size() == target_count)
break;
}
}
auto end = fine_clock::now();
console(format("Got first [%1%] unique addresses above tx [%2%] in [%3%] ms.") %
keys.size() % start_tx % ((end - start).count() / ns_to_ms));
struct out
{
// Address hash, output link, first spender link.
hash_digest address;
uint64_t output_fk;
uint64_t spend_fk;
uint64_t input_fk;
// Output's tx link, hash, and block position.
uint64_t tx_fk;
hash_digest tx_hash;
uint16_t tx_position;
// Output tx's block link, hash, and height.
uint32_t bk_fk;
hash_digest bk_hash;
uint32_t bk_height;
// Spender's tx link, hash, and block position.
uint64_t in_tx_fk;
hash_digest in_tx_hash;
uint16_t in_tx_position;
// Spender tx's block link, hash, and height.
uint32_t in_bk_fk;
hash_digest in_bk_hash;
uint32_t in_bk_height;
// Spender (first input) and output.
chain::output::cptr output{};
chain::input::cptr input{};
};
std::vector<out> outs{};
outs.reserve(target_count);
using namespace database;
start = fine_clock::now();
for (auto& key: keys)
{
auto address_it = store_.address.it(key);
if (cancel_ || address_it.self().is_terminal())
return;
do
{
table::address::record address{};
if (cancel_ || !store_.address.get(address_it.self(), address))
return;
const auto out_fk = address.output_fk;
table::output::get_parent output{};
if (!store_.output.get(out_fk, output))
return;
const auto tx_fk = output.parent_fk;
const auto block_fk = query_.to_block(tx_fk);
// Output tx block has height.
database::height_link bk_height{};
table::header::get_height bk_header{};
if (!block_fk.is_terminal())
if (!store_.header.get(block_fk, bk_header))
return;
else
bk_height = bk_header.height;
// The block is confirmed by height.
table::height::record height_record{};
const auto confirmed = store_.confirmed.get(bk_height,
height_record) && (height_record.header_fk == block_fk);
// unconfirmed tx: max height/pos, null hash, terminal/zero links.
if (!confirmed)
{
outs.emplace_back(
key,
out_fk,
max_uint64, // spend_fk
max_uint64, // input_fk
tx_fk,
null_hash,
max_uint16, // position
block_fk,
null_hash,
max_uint32, // height
// in_tx
max_uint64,
null_hash,
max_uint16, // position
// in_bk_tx
max_uint32,
null_hash,
max_uint32, // height
nullptr,
nullptr);
continue;
}
// Get confirmed output tx block position.
auto out_position = max_uint16;
table::txs::get_position txs{ {}, tx_fk };
if (!store_.txs.get(query_.to_txs_link(block_fk), txs))
return;
else
out_position = possible_narrow_cast<uint16_t>(txs.position);
// Get first spender only (may or may not be confirmed).
const auto spenders = query_.to_spenders(out_fk);
spend_link sp_fk{};
if (!spenders.empty())
sp_fk = spenders.front();
// Get spender input, tx, position, block, height.
auto in_position = max_uint16;
input_link in_fk{};
tx_link in_tx_fk{};
header_link in_bk_fk{};
height_link in_bk_height{};
if (!sp_fk.is_terminal())
{
table::spend::record spend{};
if (!store_.spend.get(sp_fk, spend))
{
return;
}
else
{
in_fk = spend.input_fk;
in_tx_fk = spend.parent_fk;
}
// Get spender tx block.
in_bk_fk = query_.to_block(in_tx_fk);
// Get in_tx position in the confirmed block.
table::txs::get_position in_txs{ {}, in_tx_fk };
if (!in_bk_fk.is_terminal())
if (!store_.txs.get(query_.to_txs_link(in_bk_fk), in_txs))
return;
else
in_position = possible_narrow_cast<uint16_t>(in_txs.position);
// Get spender input tx block height.
table::header::get_height in_bk_header{};
if (!in_bk_fk.is_terminal())
if (!store_.header.get(in_bk_fk, in_bk_header))
return;
else
in_bk_height = in_bk_header.height;
}
const auto in = query_.get_input(sp_fk);
const auto out = query_.get_output(out_fk);
// confirmed tx has block height and tx position.
outs.emplace_back(
key,
out_fk,
sp_fk,
in_fk,
tx_fk,
query_.get_tx_key(tx_fk),
out_position,
block_fk,
query_.get_header_key(block_fk),
bk_height,
in_tx_fk,
query_.get_tx_key(in_tx_fk),
in_position,
in_bk_fk,
query_.get_header_key(in_bk_fk),
in_bk_height,
out,
in);
}
while (address_it.advance());
}
end = fine_clock::now();
console(format("Got all [%1%] payments to [%2%] addresses in [%3%] ms.") %
outs.size() % keys.size() % ((end - start).count() / ns_to_ms));
}