2020-02-28 22:45:51 +01:00
|
|
|
// Copyright (c) 2020, The Monero Project
|
|
|
|
//
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// Redistribution and use in source and binary forms, with or without modification, are
|
|
|
|
// permitted provided that the following conditions are met:
|
|
|
|
//
|
|
|
|
// 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
|
|
// conditions and the following disclaimer.
|
|
|
|
//
|
|
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
|
|
// of conditions and the following disclaimer in the documentation and/or other
|
|
|
|
// materials provided with the distribution.
|
|
|
|
//
|
|
|
|
// 3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
|
|
// used to endorse or promote products derived from this software without specific
|
|
|
|
// prior written permission.
|
|
|
|
//
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
|
|
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
2020-03-17 00:59:26 +01:00
|
|
|
#include <boost/preprocessor/stringize.hpp>
|
2020-02-28 22:45:51 +01:00
|
|
|
#include <gtest/gtest.h>
|
2020-03-17 00:59:26 +01:00
|
|
|
#include <rapidjson/document.h>
|
2020-02-28 22:45:51 +01:00
|
|
|
|
2020-03-17 00:59:26 +01:00
|
|
|
#include "cryptonote_basic/account.h"
|
|
|
|
#include "cryptonote_basic/cryptonote_basic.h"
|
|
|
|
#include "cryptonote_basic/events.h"
|
|
|
|
#include "cryptonote_basic/cryptonote_format_utils.h"
|
|
|
|
#include "json_serialization.h"
|
|
|
|
#include "net/zmq.h"
|
2020-02-28 22:45:51 +01:00
|
|
|
#include "rpc/message.h"
|
2020-03-17 00:59:26 +01:00
|
|
|
#include "rpc/zmq_pub.h"
|
|
|
|
#include "rpc/zmq_server.h"
|
2020-02-28 22:45:51 +01:00
|
|
|
#include "serialization/json_object.h"
|
|
|
|
|
2020-03-17 00:59:26 +01:00
|
|
|
#define MASSERT(...) \
|
|
|
|
if (!(__VA_ARGS__)) \
|
|
|
|
return testing::AssertionFailure() << BOOST_PP_STRINGIZE(__VA_ARGS__)
|
|
|
|
|
2020-02-28 22:45:51 +01:00
|
|
|
TEST(ZmqFullMessage, InvalidRequest)
|
|
|
|
{
|
|
|
|
EXPECT_THROW(
|
|
|
|
(cryptonote::rpc::FullMessage{"{\"jsonrpc\":\"2.0\",\"id\":0,\"params\":[]}", true}),
|
|
|
|
cryptonote::json::MISSING_KEY
|
|
|
|
);
|
|
|
|
EXPECT_THROW(
|
|
|
|
(cryptonote::rpc::FullMessage{"{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":3,\"params\":[]}", true}),
|
|
|
|
cryptonote::json::WRONG_TYPE
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(ZmqFullMessage, Request)
|
|
|
|
{
|
|
|
|
static constexpr const char request[] = "{\"jsonrpc\":\"2.0\",\"id\":0,\"method\":\"foo\",\"params\":[]}";
|
|
|
|
EXPECT_NO_THROW(
|
|
|
|
(cryptonote::rpc::FullMessage{request, true})
|
|
|
|
);
|
|
|
|
|
|
|
|
cryptonote::rpc::FullMessage parsed{request, true};
|
|
|
|
EXPECT_STREQ("foo", parsed.getRequestType().c_str());
|
|
|
|
}
|
2020-03-17 00:59:26 +01:00
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
|
|
|
using published_json = std::pair<std::string, rapidjson::Document>;
|
|
|
|
|
|
|
|
constexpr const char inproc_pub[] = "inproc://dummy_pub";
|
|
|
|
|
|
|
|
net::zmq::socket create_socket(void* ctx, const char* address)
|
|
|
|
{
|
|
|
|
net::zmq::socket sock{zmq_socket(ctx, ZMQ_PAIR)};
|
|
|
|
if (!sock)
|
|
|
|
MONERO_ZMQ_THROW("failed to create socket");
|
|
|
|
if (zmq_bind(sock.get(), address) != 0)
|
|
|
|
MONERO_ZMQ_THROW("socket bind failure");
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> get_messages(void* socket, int count = -1)
|
|
|
|
{
|
|
|
|
std::vector<std::string> out;
|
|
|
|
for ( ; count || count < 0; --count)
|
|
|
|
{
|
|
|
|
expect<std::string> next = net::zmq::receive(socket, (count < 0 ? ZMQ_DONTWAIT : 0));
|
|
|
|
if (next == net::zmq::make_error_code(EAGAIN))
|
|
|
|
return out;
|
|
|
|
out.push_back(std::move(*next));
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<published_json> get_published(void* socket, int count = -1)
|
|
|
|
{
|
|
|
|
std::vector<published_json> out;
|
|
|
|
|
|
|
|
const auto messages = get_messages(socket, count);
|
|
|
|
out.reserve(messages.size());
|
|
|
|
|
|
|
|
for (const std::string& message : messages)
|
|
|
|
{
|
|
|
|
const char* split = std::strchr(message.c_str(), ':');
|
|
|
|
if (!split)
|
|
|
|
throw std::runtime_error{"Invalid ZMQ/Pub message"};
|
|
|
|
|
|
|
|
out.emplace_back();
|
|
|
|
out.back().first = {message.c_str(), split};
|
|
|
|
if (out.back().second.Parse(split + 1).HasParseError())
|
|
|
|
throw std::runtime_error{"Failed to parse ZMQ/Pub message"};
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
testing::AssertionResult compare_full_txpool(epee::span<const cryptonote::txpool_event> events, const published_json& pub)
|
|
|
|
{
|
|
|
|
MASSERT(pub.first == "json-full-txpool_add");
|
|
|
|
MASSERT(pub.second.IsArray());
|
|
|
|
MASSERT(pub.second.Size() <= events.size());
|
|
|
|
|
|
|
|
std::size_t i = 0;
|
|
|
|
for (const cryptonote::txpool_event& event : events)
|
|
|
|
{
|
|
|
|
MASSERT(i <= pub.second.Size());
|
|
|
|
if (!event.res)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
cryptonote::transaction tx{};
|
|
|
|
cryptonote::json::fromJsonValue(pub.second[i], tx);
|
|
|
|
|
|
|
|
crypto::hash id{};
|
|
|
|
MASSERT(cryptonote::get_transaction_hash(event.tx, id));
|
|
|
|
MASSERT(cryptonote::get_transaction_hash(tx, id));
|
|
|
|
MASSERT(event.tx.hash == tx.hash);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
return testing::AssertionSuccess();
|
|
|
|
}
|
|
|
|
|
|
|
|
testing::AssertionResult compare_minimal_txpool(epee::span<const cryptonote::txpool_event> events, const published_json& pub)
|
|
|
|
{
|
|
|
|
MASSERT(pub.first == "json-minimal-txpool_add");
|
|
|
|
MASSERT(pub.second.IsArray());
|
|
|
|
MASSERT(pub.second.Size() <= events.size());
|
|
|
|
|
|
|
|
std::size_t i = 0;
|
|
|
|
for (const cryptonote::txpool_event& event : events)
|
|
|
|
{
|
|
|
|
MASSERT(i <= pub.second.Size());
|
|
|
|
if (!event.res)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
std::size_t actual_size = 0;
|
|
|
|
crypto::hash actual_id{};
|
|
|
|
|
|
|
|
MASSERT(pub.second[i].IsObject());
|
|
|
|
GET_FROM_JSON_OBJECT(pub.second[i], actual_id, id);
|
|
|
|
GET_FROM_JSON_OBJECT(pub.second[i], actual_size, blob_size);
|
|
|
|
|
|
|
|
std::size_t expected_size = 0;
|
|
|
|
crypto::hash expected_id{};
|
|
|
|
MASSERT(cryptonote::get_transaction_hash(event.tx, expected_id, expected_size));
|
|
|
|
MASSERT(expected_size == actual_size);
|
|
|
|
MASSERT(expected_id == actual_id);
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
return testing::AssertionSuccess();
|
|
|
|
}
|
|
|
|
|
|
|
|
testing::AssertionResult compare_full_block(const epee::span<const cryptonote::block> expected, const published_json& pub)
|
|
|
|
{
|
|
|
|
MASSERT(pub.first == "json-full-chain_main");
|
|
|
|
MASSERT(pub.second.IsArray());
|
|
|
|
|
|
|
|
std::vector<cryptonote::block> actual;
|
|
|
|
cryptonote::json::fromJsonValue(pub.second, actual);
|
|
|
|
|
|
|
|
MASSERT(expected.size() == actual.size());
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < expected.size(); ++i)
|
|
|
|
{
|
|
|
|
crypto::hash id;
|
|
|
|
MASSERT(cryptonote::get_block_hash(expected[i], id));
|
|
|
|
MASSERT(cryptonote::get_block_hash(actual[i], id));
|
|
|
|
MASSERT(expected[i].hash == actual[i].hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
return testing::AssertionSuccess();
|
|
|
|
}
|
|
|
|
|
|
|
|
testing::AssertionResult compare_minimal_block(std::size_t height, const epee::span<const cryptonote::block> expected, const published_json& pub)
|
|
|
|
{
|
|
|
|
MASSERT(pub.first == "json-minimal-chain_main");
|
|
|
|
MASSERT(pub.second.IsObject());
|
|
|
|
MASSERT(!expected.empty());
|
|
|
|
|
|
|
|
std::size_t actual_height = 0;
|
|
|
|
crypto::hash actual_id{};
|
|
|
|
crypto::hash actual_prev_id{};
|
|
|
|
std::vector<crypto::hash> actual_ids{};
|
|
|
|
GET_FROM_JSON_OBJECT(pub.second, actual_height, first_height);
|
|
|
|
GET_FROM_JSON_OBJECT(pub.second, actual_prev_id, first_prev_id);
|
|
|
|
GET_FROM_JSON_OBJECT(pub.second, actual_ids, ids);
|
|
|
|
|
|
|
|
MASSERT(height == actual_height);
|
|
|
|
MASSERT(expected[0].prev_id == actual_prev_id);
|
|
|
|
MASSERT(expected.size() == actual_ids.size());
|
|
|
|
|
|
|
|
for (std::size_t i = 0; i < expected.size(); ++i)
|
|
|
|
{
|
|
|
|
crypto::hash id;
|
|
|
|
MASSERT(cryptonote::get_block_hash(expected[i], id));
|
|
|
|
MASSERT(id == actual_ids[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
return testing::AssertionSuccess();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct zmq_base : public testing::Test
|
|
|
|
{
|
|
|
|
cryptonote::account_base acct;
|
|
|
|
|
|
|
|
zmq_base()
|
|
|
|
: testing::Test(), acct()
|
|
|
|
{
|
|
|
|
acct.generate();
|
|
|
|
}
|
|
|
|
|
|
|
|
cryptonote::transaction make_miner_transaction()
|
|
|
|
{
|
|
|
|
return test::make_miner_transaction(acct.get_keys().m_account_address);
|
|
|
|
}
|
|
|
|
|
|
|
|
cryptonote::transaction make_transaction(const std::vector<cryptonote::account_public_address>& destinations)
|
|
|
|
{
|
|
|
|
return test::make_transaction(acct.get_keys(), {make_miner_transaction()}, destinations, true, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
cryptonote::transaction make_transaction()
|
|
|
|
{
|
|
|
|
cryptonote::account_base temp_account;
|
|
|
|
temp_account.generate();
|
|
|
|
return make_transaction({temp_account.get_keys().m_account_address});
|
|
|
|
}
|
|
|
|
|
|
|
|
cryptonote::block make_block()
|
|
|
|
{
|
|
|
|
cryptonote::block block{};
|
|
|
|
block.major_version = 1;
|
|
|
|
block.minor_version = 3;
|
|
|
|
block.timestamp = 100;
|
|
|
|
block.prev_id = crypto::rand<crypto::hash>();
|
|
|
|
block.nonce = 100;
|
|
|
|
block.miner_tx = make_miner_transaction();
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct zmq_pub : public zmq_base
|
|
|
|
{
|
|
|
|
net::zmq::context ctx;
|
|
|
|
net::zmq::socket relay;
|
|
|
|
net::zmq::socket dummy_pub;
|
|
|
|
net::zmq::socket dummy_client;
|
|
|
|
std::shared_ptr<cryptonote::listener::zmq_pub> pub;
|
|
|
|
|
|
|
|
zmq_pub()
|
|
|
|
: zmq_base(),
|
|
|
|
ctx(zmq_init(1)),
|
|
|
|
relay(create_socket(ctx.get(), cryptonote::listener::zmq_pub::relay_endpoint())),
|
|
|
|
dummy_pub(create_socket(ctx.get(), inproc_pub)),
|
|
|
|
dummy_client(zmq_socket(ctx.get(), ZMQ_PAIR)),
|
|
|
|
pub(std::make_shared<cryptonote::listener::zmq_pub>(ctx.get()))
|
|
|
|
{
|
|
|
|
if (!dummy_client)
|
|
|
|
MONERO_ZMQ_THROW("failed to create socket");
|
|
|
|
if (zmq_connect(dummy_client.get(), inproc_pub) != 0)
|
|
|
|
MONERO_ZMQ_THROW("failed to connect to dummy pub");
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void TearDown() override final
|
|
|
|
{
|
|
|
|
EXPECT_EQ(0u, get_messages(relay.get()).size());
|
|
|
|
EXPECT_EQ(0u, get_messages(dummy_client.get()).size());
|
|
|
|
}
|
|
|
|
|
|
|
|
template<std::size_t N>
|
|
|
|
bool sub_request(const char (&topic)[N])
|
|
|
|
{
|
|
|
|
return pub->sub_request({topic, N - 1});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct dummy_handler final : cryptonote::rpc::RpcHandler
|
|
|
|
{
|
|
|
|
dummy_handler()
|
|
|
|
: cryptonote::rpc::RpcHandler()
|
|
|
|
{}
|
|
|
|
|
2020-05-30 03:59:58 +02:00
|
|
|
virtual epee::byte_slice handle(std::string&& request) override final
|
2020-03-17 00:59:26 +01:00
|
|
|
{
|
|
|
|
throw std::logic_error{"not implemented"};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct zmq_server : public zmq_base
|
|
|
|
{
|
|
|
|
dummy_handler handler;
|
|
|
|
cryptonote::rpc::ZmqServer server;
|
|
|
|
std::shared_ptr<cryptonote::listener::zmq_pub> pub;
|
|
|
|
net::zmq::socket sub;
|
|
|
|
|
|
|
|
zmq_server()
|
|
|
|
: zmq_base(),
|
|
|
|
handler(),
|
|
|
|
server(handler),
|
|
|
|
pub(),
|
|
|
|
sub()
|
|
|
|
{
|
|
|
|
void* ctx = server.init_rpc({}, {});
|
|
|
|
if (!ctx)
|
|
|
|
throw std::runtime_error{"init_rpc failure"};
|
|
|
|
|
|
|
|
const std::string endpoint = inproc_pub;
|
|
|
|
pub = server.init_pub({std::addressof(endpoint), 1});
|
|
|
|
if (!pub)
|
|
|
|
throw std::runtime_error{"failed to initiaze zmq/pub"};
|
|
|
|
|
|
|
|
sub.reset(zmq_socket(ctx, ZMQ_SUB));
|
|
|
|
if (!sub)
|
|
|
|
MONERO_ZMQ_THROW("failed to create socket");
|
|
|
|
if (zmq_connect(sub.get(), inproc_pub) != 0)
|
|
|
|
MONERO_ZMQ_THROW("failed to connect to dummy pub");
|
|
|
|
|
|
|
|
server.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void TearDown() override final
|
|
|
|
{
|
|
|
|
EXPECT_EQ(0u, get_messages(sub.get()).size());
|
|
|
|
sub.reset();
|
|
|
|
pub.reset();
|
|
|
|
server.stop();
|
|
|
|
}
|
|
|
|
|
|
|
|
template<std::size_t N>
|
|
|
|
void subscribe(const char (&topic)[N])
|
|
|
|
{
|
|
|
|
if (zmq_setsockopt(sub.get(), ZMQ_SUBSCRIBE, topic, N - 1) != 0)
|
|
|
|
MONERO_ZMQ_THROW("failed to subscribe");
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, InvalidContext)
|
|
|
|
{
|
|
|
|
EXPECT_THROW(cryptonote::listener::zmq_pub{nullptr}, std::logic_error);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, NoBlocking)
|
|
|
|
{
|
|
|
|
EXPECT_FALSE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, DefaultDrop)
|
|
|
|
{
|
|
|
|
EXPECT_EQ(0u, pub->send_txpool_add({{make_transaction(), {}, true}}));
|
|
|
|
|
|
|
|
const cryptonote::block bl = make_block();
|
|
|
|
EXPECT_EQ(0u,pub->send_chain_main(5, {std::addressof(bl), 1}));
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(5, {std::addressof(bl), 1}));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonFullTxpool)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json-full-txpool_add";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
|
|
|
|
std::vector<cryptonote::txpool_event> events
|
|
|
|
{
|
|
|
|
{make_transaction(), {}, true}, {make_transaction(), {}, true}
|
|
|
|
};
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_EQ(1u, pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonMinimalTxpool)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json-minimal-txpool_add";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
|
|
|
|
std::vector<cryptonote::txpool_event> events
|
|
|
|
{
|
|
|
|
{make_transaction(), {}, true}, {make_transaction(), {}, true}
|
|
|
|
};
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_EQ(1u, pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonFullChain)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json-full-chain_main";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
|
|
|
|
const std::array<cryptonote::block, 2> blocks{{make_block(), make_block()}};
|
|
|
|
|
|
|
|
EXPECT_EQ(1u, pub->send_chain_main(100, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonMinimalChain)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json-minimal-chain_main";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
|
|
|
|
const std::array<cryptonote::block, 2> blocks{{make_block(), make_block()}};
|
|
|
|
|
|
|
|
EXPECT_EQ(1u, pub->send_chain_main(100, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_block(100, epee::to_span(blocks), pubs.front()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_block(533, epee::to_span(blocks), pubs.front()));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonFullAll)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json-full";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
{
|
|
|
|
std::vector<cryptonote::txpool_event> events
|
|
|
|
{
|
|
|
|
{make_transaction(), {}, true}, {make_transaction(), {}, true}
|
|
|
|
};
|
|
|
|
|
|
|
|
EXPECT_EQ(1u, pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_NO_THROW(pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
const std::array<cryptonote::block, 2> blocks{{make_block(), make_block()}};
|
|
|
|
|
|
|
|
EXPECT_EQ(1u, pub->send_chain_main(100, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonMinimalAll)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json-minimal";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
|
|
|
|
{
|
|
|
|
std::vector<cryptonote::txpool_event> events
|
|
|
|
{
|
|
|
|
{make_transaction(), {}, true}, {make_transaction(), {}, true}
|
|
|
|
};
|
|
|
|
|
|
|
|
EXPECT_EQ(1u, pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_NO_THROW(pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
const std::array<cryptonote::block, 2> blocks{{make_block(), make_block()}};
|
|
|
|
|
|
|
|
EXPECT_EQ(1u, pub->send_chain_main(100, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_block(100, epee::to_span(blocks), pubs.front()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(1u, pubs.size());
|
|
|
|
ASSERT_LE(1u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_block(533, epee::to_span(blocks), pubs.front()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonAll)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
|
|
|
|
{
|
|
|
|
std::vector<cryptonote::txpool_event> events
|
|
|
|
{
|
|
|
|
{make_transaction(), {}, true}, {make_transaction(), {}, true}
|
|
|
|
};
|
|
|
|
|
|
|
|
EXPECT_EQ(1u, pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(2u, pubs.size());
|
|
|
|
ASSERT_LE(2u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.back()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(2u, pubs.size());
|
|
|
|
ASSERT_LE(2u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.back()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_EQ(1u, pub->send_txpool_add(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(2u, pubs.size());
|
|
|
|
ASSERT_LE(2u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.back()));
|
|
|
|
|
|
|
|
events.at(0).res = false;
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(events));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(2u, pubs.size());
|
|
|
|
ASSERT_LE(2u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.back()));
|
|
|
|
}
|
|
|
|
{
|
|
|
|
const std::array<cryptonote::block, 1> blocks{{make_block()}};
|
|
|
|
|
|
|
|
EXPECT_EQ(2u, pub->send_chain_main(100, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
auto pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(2u, pubs.size());
|
|
|
|
ASSERT_LE(2u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
|
|
|
|
EXPECT_TRUE(compare_minimal_block(100, epee::to_span(blocks), pubs.back()));
|
|
|
|
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
EXPECT_TRUE(pub->relay_to_pub(relay.get(), dummy_pub.get()));
|
|
|
|
|
|
|
|
pubs = get_published(dummy_client.get());
|
|
|
|
EXPECT_EQ(2u, pubs.size());
|
|
|
|
ASSERT_LE(2u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_full_block(epee::to_span(blocks), pubs.front()));
|
|
|
|
EXPECT_TRUE(compare_minimal_block(533, epee::to_span(blocks), pubs.back()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonChainWeakPtrSkip)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
|
|
|
|
const std::array<cryptonote::block, 1> blocks{{make_block()}};
|
|
|
|
|
|
|
|
pub.reset();
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::chain_main{pub}(533, epee::to_span(blocks)));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_pub, JsonTxpoolWeakPtrSkip)
|
|
|
|
{
|
|
|
|
static constexpr const char topic[] = "\1json";
|
|
|
|
|
|
|
|
ASSERT_TRUE(sub_request(topic));
|
|
|
|
|
|
|
|
std::vector<cryptonote::txpool_event> events
|
|
|
|
{
|
|
|
|
{make_transaction(), {}, true}, {make_transaction(), {}, true}
|
|
|
|
};
|
|
|
|
|
|
|
|
pub.reset();
|
|
|
|
EXPECT_NO_THROW(cryptonote::listener::zmq_pub::txpool_add{pub}(std::move(events)));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_F(zmq_server, pub)
|
|
|
|
{
|
|
|
|
subscribe("json-minimal");
|
|
|
|
|
|
|
|
std::vector<cryptonote::txpool_event> events
|
|
|
|
{
|
|
|
|
{make_transaction(), {}, true}, {make_transaction(), {}, true}
|
|
|
|
};
|
|
|
|
|
|
|
|
const std::array<cryptonote::block, 1> blocks{{make_block()}};
|
|
|
|
|
|
|
|
ASSERT_EQ(1u, pub->send_txpool_add(events));
|
|
|
|
ASSERT_EQ(1u, pub->send_chain_main(200, epee::to_span(blocks)));
|
|
|
|
|
|
|
|
auto pubs = get_published(sub.get(), 2);
|
|
|
|
EXPECT_EQ(2u, pubs.size());
|
|
|
|
ASSERT_LE(2u, pubs.size());
|
|
|
|
EXPECT_TRUE(compare_minimal_txpool(epee::to_span(events), pubs.front()));
|
|
|
|
EXPECT_TRUE(compare_minimal_block(200, epee::to_span(blocks), pubs.back()));
|
|
|
|
}
|