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
49 changes: 36 additions & 13 deletions include/bitcoin/node/protocols/protocol_explore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,25 +60,47 @@ class BCN_API protocol_explore

/// REST interface handlers.

bool handle_get_top(const code& ec, interface::top,
uint8_t version, uint8_t media) NOEXCEPT;

bool handle_get_block(const code& ec, interface::block,
uint8_t version, uint8_t media, std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height, bool witness) NOEXCEPT;
bool handle_get_header(const code& ec, interface::header,
bool handle_get_block_header(const code& ec, interface::block_header,
uint8_t version, uint8_t media, std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_block_txs(const code& ec, interface::block_txs,
uint8_t version, uint8_t media, std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_block_fees(const code& ec, interface::block_fees,
uint8_t version, uint8_t media, std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_block_filter(const code& ec, interface::block_filter,
uint8_t version, uint8_t media, uint8_t type,
std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_block_filter_hash(const code& ec,
interface::block_filter_hash, uint8_t version, uint8_t media,
uint8_t type, std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_block_filter_header(const code& ec,
interface::block_filter_header, uint8_t version, uint8_t media,
uint8_t type, std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_block_tx(const code& ec, interface::block_tx,
uint8_t version, uint8_t media, uint32_t position,
std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height, bool witness) NOEXCEPT;
bool handle_get_transaction(const code& ec, interface::transaction,

bool handle_get_tx(const code& ec, interface::tx,
uint8_t version, uint8_t media, const system::hash_cptr& hash,
bool witness) NOEXCEPT;
bool handle_get_tx_block(const code& ec, interface::tx_block,
uint8_t version, uint8_t media,
const system::hash_cptr& hash) NOEXCEPT;
bool handle_get_tx_fee(const code& ec, interface::tx_fee,
uint8_t version, uint8_t media,
const system::hash_cptr& hash) NOEXCEPT;

bool handle_get_inputs(const code& ec, interface::inputs,
uint8_t version, uint8_t media, const system::hash_cptr& hash,
Expand Down Expand Up @@ -112,19 +134,20 @@ class BCN_API protocol_explore
bool handle_get_address(const code& ec, interface::address,
uint8_t version, uint8_t media,
const system::hash_cptr& hash) NOEXCEPT;
bool handle_get_filter(const code& ec, interface::filter, uint8_t version,
uint8_t media, uint8_t type, std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_filter_hash(const code& ec, interface::filter_hash,
uint8_t version, uint8_t media, uint8_t type,
std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_filter_header(const code& ec, interface::filter_header,
uint8_t version, uint8_t media, uint8_t type,
std::optional<system::hash_cptr> hash,
std::optional<uint32_t> height) NOEXCEPT;
bool handle_get_address_confirmed(const code& ec,
interface::address_confirmed, uint8_t version, uint8_t media,
const system::hash_cptr& hash) NOEXCEPT;
bool handle_get_address_unconfirmed(const code& ec,
interface::address_unconfirmed, uint8_t version, uint8_t media,
const system::hash_cptr& hash) NOEXCEPT;
bool handle_get_address_balance(const code& ec,
interface::address_balance, uint8_t version, uint8_t media,
const system::hash_cptr& hash) NOEXCEPT;

private:
void inject(boost::json::value& out, std::optional<uint32_t> height,
const database::header_link& link) const NOEXCEPT;

database::header_link to_header(const std::optional<uint32_t>& height,
const std::optional<system::hash_cptr>& hash) NOEXCEPT;

Expand Down
140 changes: 69 additions & 71 deletions src/parse/target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ static hash_cptr to_hash(const std::string_view& token) NOEXCEPT
emplace_shared<const hash_digest>(std::move(out)) : hash_cptr{};
}

static hash_cptr to_base16(const std::string_view& token) NOEXCEPT
{
hash_digest out{};
return decode_base16(out, token) ?
emplace_shared<const hash_digest>(std::move(out)) : hash_cptr{};
}

code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
{
const auto clean = split(path, "?", false, false).front();
Expand Down Expand Up @@ -84,38 +91,21 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
// transaction, address, inputs, and outputs are identical excluding names;
// input and output are identical excluding names; block is unique.
const auto target = segments[segment++];
if (target == "address")
if (target == "top")
{
if (segment == segments.size())
return error::missing_hash;

const auto hash = to_hash(segments[segment++]);
if (!hash) return error::invalid_hash;

method = "address";
params["hash"] = hash;
method = "top";
}
else if (target == "inputs")
else if (target == "address")
{
if (segment == segments.size())
return error::missing_hash;

const auto hash = to_hash(segments[segment++]);
if (!hash) return error::invalid_hash;

method = "inputs";
params["hash"] = hash;
}
else if (target == "outputs")
{
if (segment == segments.size())
return error::missing_hash;

const auto hash = to_hash(segments[segment++]);
if (!hash) return error::invalid_hash;
// address hash is a single sha256, and conventionally not reversed.
const auto base16 = to_base16(segments[segment++]);
if (!base16) return error::invalid_hash;

method = "outputs";
params["hash"] = hash;
method = "address";
params["hash"] = base16;
}
else if (target == "input")
{
Expand All @@ -126,28 +116,32 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
if (!hash) return error::invalid_hash;

params["hash"] = hash;
if (segment == segments.size())
return error::missing_component;

const auto component = segments[segment++];
uint32_t index{};
if (!to_number(index, component))
return error::invalid_number;

params["index"] = index;
if (segment == segments.size())
{
method = "input";
method = "inputs";
}
else
{
const auto subcomponent = segments[segment++];
if (subcomponent == "script")
method = "input_script";
else if (subcomponent == "witness")
method = "input_witness";
const auto component = segments[segment++];
uint32_t index{};
if (!to_number(index, component))
return error::invalid_number;

params["index"] = index;
if (segment == segments.size())
{
method = "input";
}
else
return error::invalid_subcomponent;
{
const auto subcomponent = segments[segment++];
if (subcomponent == "script")
method = "input_script";
else if (subcomponent == "witness")
method = "input_witness";
else
return error::invalid_subcomponent;
}
}
}
else if (target == "output")
Expand All @@ -159,33 +153,37 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
if (!hash) return error::invalid_hash;

params["hash"] = hash;
if (segment == segments.size())
return error::missing_component;

const auto component = segments[segment++];
uint32_t index{};
if (!to_number(index, component))
return error::invalid_number;

params["index"] = index;
if (segment == segments.size())
{
method = "output";
method = "outputs";
}
else
{
const auto subcomponent = segments[segment++];
if (subcomponent == "script")
method = "output_script";
else if (subcomponent == "spender")
method = "output_spender";
else if (subcomponent == "spenders")
method = "output_spenders";
const auto component = segments[segment++];
uint32_t index{};
if (!to_number(index, component))
return error::invalid_number;

params["index"] = index;
if (segment == segments.size())
{
method = "output";
}
else
return error::invalid_subcomponent;
{
const auto subcomponent = segments[segment++];
if (subcomponent == "script")
method = "output_script";
else if (subcomponent == "spender")
method = "output_spender";
else if (subcomponent == "spenders")
method = "output_spenders";
else
return error::invalid_subcomponent;
}
}
}
else if (target == "transaction")
else if (target == "tx")
{
if (segment == segments.size())
return error::missing_hash;
Expand All @@ -196,13 +194,15 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
params["hash"] = hash;
if (segment == segments.size())
{
method = "transaction";
method = "tx";
}
else
{
const auto component = segments[segment++];
if (component == "block")
method = "tx_block";
else if (component == "fee")
method = "tx_fee";
else
return error::invalid_component;
}
Expand All @@ -221,8 +221,6 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
const auto hash = to_hash(segments[segment++]);
if (!hash) return error::invalid_hash;

// nullables can be implicit.
////params["height"] = null_t{};
params["hash"] = hash;
}
else if (by == "height")
Expand All @@ -234,8 +232,6 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
if (!to_number(height, segments[segment++]))
return error::invalid_number;

// nullables can be implicit.
////params["hash"] = null_t{};
params["height"] = height;
}
else
Expand All @@ -250,7 +246,7 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
else
{
const auto component = segments[segment++];
if (component == "transaction")
if (component == "tx")
{
if (segment == segments.size())
return error::missing_position;
Expand All @@ -263,9 +259,11 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
method = "block_tx";
}
else if (component == "header")
method = "header";
else if (component == "transactions")
method = "block_header";
else if (component == "txs")
method = "block_txs";
else if (component == "fees")
method = "block_fees";
else if (component == "filter")
{
if (segment == segments.size())
Expand All @@ -278,15 +276,15 @@ code parse_target(request_t& out, const std::string_view& path) NOEXCEPT
params["type"] = type;
if (segment == segments.size())
{
method = "filter";
method = "block_filter";
}
else
{
const auto subcomponent = segments[segment++];
if (subcomponent == "hash")
method = "filter_hash";
method = "block_filter_hash";
else if (subcomponent == "header")
method = "filter_header";
method = "block_filter_header";
else
return error::invalid_subcomponent;
}
Expand Down
Loading
Loading