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
66 changes: 35 additions & 31 deletions include/bitcoin/server/interfaces/explore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ struct explore_methods
{
static constexpr std::tuple methods
{
method<"configuration", uint8_t, uint8_t>{ "version", "media" },

method<"top", uint8_t, uint8_t>{ "version", "media" },
method<"block", uint8_t, uint8_t, nullable<system::hash_cptr>, nullable<uint32_t>, optional<true>>{ "version", "media", "hash", "height", "witness" },
method<"block_header", uint8_t, uint8_t, nullable<system::hash_cptr>, nullable<uint32_t>>{ "version", "media", "hash", "height" },
Expand Down Expand Up @@ -70,37 +72,39 @@ struct explore_methods

// Derive this from above in c++26 using reflection.

using top = at<0>;

using block = at<1>;
using block_header = at<2>;
using block_header_context = at<3>;
using block_details = at<4>;
using block_txs = at<5>;
using block_filter = at<6>;
using block_filter_hash = at<7>;
using block_filter_header = at<8>;
using block_tx = at<9>;

using tx = at<10>;
using tx_header = at<11>;
using tx_details = at<12>;

using inputs = at<13>;
using input = at<14>;
using input_script = at<15>;
using input_witness = at<16>;

using outputs = at<17>;
using output = at<18>;
using output_script = at<19>;
using output_spender = at<20>;
using output_spenders = at<21>;

using address = at<22>;
using address_confirmed = at<23>;
using address_unconfirmed = at<24>;
using address_balance = at<25>;
using configuration = at<0>;

using top = at<1>;

using block = at<2>;
using block_header = at<3>;
using block_header_context = at<4>;
using block_details = at<5>;
using block_txs = at<6>;
using block_filter = at<7>;
using block_filter_hash = at<8>;
using block_filter_header = at<9>;
using block_tx = at<10>;

using tx = at<11>;
using tx_header = at<12>;
using tx_details = at<13>;

using inputs = at<14>;
using input = at<15>;
using input_script = at<16>;
using input_witness = at<17>;

using outputs = at<18>;
using output = at<19>;
using output_script = at<20>;
using output_spender = at<21>;
using output_spenders = at<22>;

using address = at<23>;
using address_confirmed = at<24>;
using address_unconfirmed = at<25>;
using address_balance = at<26>;
};

/// ?format=data|text|json (via query string).
Expand Down
3 changes: 3 additions & 0 deletions include/bitcoin/server/protocols/protocol_explore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class BCS_API protocol_explore

/// REST interface handlers.

bool handle_get_configuration(const code& ec, interface::configuration,
uint8_t version, uint8_t media) NOEXCEPT;

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

Expand Down
6 changes: 5 additions & 1 deletion src/parsers/explore_target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,11 @@ code explore_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 == "top")
if (target == "configuration")
{
method = "configuration";
}
else if (target == "top")
{
method = "top";
}
Expand Down
31 changes: 29 additions & 2 deletions src/protocols/protocol_explore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ void protocol_explore::start() NOEXCEPT
if (started())
return;

SUBSCRIBE_EXPLORE(handle_get_top, _1, _2, _3, _4);
SUBSCRIBE_EXPLORE(handle_get_configuration, _1, _2, _3, _4);

SUBSCRIBE_EXPLORE(handle_get_top, _1, _2, _3, _4);
SUBSCRIBE_EXPLORE(handle_get_block, _1, _2, _3, _4, _5, _6, _7);
SUBSCRIBE_EXPLORE(handle_get_block_header, _1, _2, _3, _4, _5, _6);
SUBSCRIBE_EXPLORE(handle_get_block_header_context, _1, _2, _3, _4, _5, _6);
Expand Down Expand Up @@ -147,7 +148,7 @@ bool protocol_explore::try_dispatch_object(const http::request& request) NOEXCEP
return true;
}

// Handlers.
// Serialization.
// ----------------------------------------------------------------------------

constexpr auto data = to_value(http::media_type::application_octet_stream);
Expand Down Expand Up @@ -232,6 +233,32 @@ std::string to_hex_ptr_array(const Collection& collection, size_t size,
return out;
}

// Handlers.
// ----------------------------------------------------------------------------

bool protocol_explore::handle_get_configuration(const code& ec,
interface::configuration, uint8_t, uint8_t media) NOEXCEPT
{
if (stopped(ec))
return false;

if (media != json)
{
send_not_acceptable();
return true;
}

const auto& query = archive();

value model{};
auto& object = model.emplace_object();
object.emplace("address", query.address_enabled());
object.emplace("filter", query.filter_enabled());

send_json(std::move(model), 25);
return true;
}

bool protocol_explore::handle_get_top(const code& ec, interface::top,
uint8_t, uint8_t media) NOEXCEPT
{
Expand Down
56 changes: 56 additions & 0 deletions test/parsers/explore_target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,62 @@ BOOST_AUTO_TEST_CASE(parsers__explore_target__invalid_target__invalid_target)
BOOST_REQUIRE_EQUAL(explore_target(out, "/v3/invalid"), server::error::invalid_target);
}

// configuration

BOOST_AUTO_TEST_CASE(parsers__explore_target__configuration_valid__expected)
{
const std::string path = "/v42/configuration";

request_t request{};
BOOST_REQUIRE(!explore_target(request, path));
BOOST_REQUIRE_EQUAL(request.method, "configuration");
BOOST_REQUIRE(request.params.has_value());

const auto& params = request.params.value();
BOOST_REQUIRE(std::holds_alternative<object_t>(params));

const auto& object = std::get<object_t>(request.params.value());
BOOST_REQUIRE_EQUAL(object.size(), 1u);

const auto version = std::get<uint8_t>(object.at("version").value());
BOOST_REQUIRE_EQUAL(version, 42u);
}

BOOST_AUTO_TEST_CASE(parsers__explore_target__configuration_extra_segment__extra_segment)
{
const std::string path = "/v3/configuration/extra";
request_t out{};
BOOST_REQUIRE_EQUAL(explore_target(out, path), server::error::extra_segment);
}

// top

BOOST_AUTO_TEST_CASE(parsers__explore_target__top_valid__expected)
{
const std::string path = "/v42/top";

request_t request{};
BOOST_REQUIRE(!explore_target(request, path));
BOOST_REQUIRE_EQUAL(request.method, "top");
BOOST_REQUIRE(request.params.has_value());

const auto& params = request.params.value();
BOOST_REQUIRE(std::holds_alternative<object_t>(params));

const auto& object = std::get<object_t>(request.params.value());
BOOST_REQUIRE_EQUAL(object.size(), 1u);

const auto version = std::get<uint8_t>(object.at("version").value());
BOOST_REQUIRE_EQUAL(version, 42u);
}

BOOST_AUTO_TEST_CASE(parsers__explore_target__top_extra_segment__extra_segment)
{
const std::string path = "/v3/top/extra";
request_t out{};
BOOST_REQUIRE_EQUAL(explore_target(out, path), server::error::extra_segment);
}

// block/height

BOOST_AUTO_TEST_CASE(parsers__explore_target__block_height_valid__expected)
Expand Down
Loading