-
Notifications
You must be signed in to change notification settings - Fork 8
/
main.cpp
176 lines (168 loc) · 5.25 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include <future>
#include <boost/filesystem.hpp>
#include <signal.h>
#include <bitcoin/bitcoin.hpp>
#include <czmq++/czmqpp.hpp>
#include "btcnet.hpp"
using bc::log_info;
using bc::log_warning;
using bc::log_fatal;
constexpr const char* server_cert_filename = "brc_server_cert";
// Milliseconds
constexpr long poll_sleep_interval = 1000;
bool stopped = false;
void interrupt_handler(int)
{
log_info() << "Stopping... Please wait.";
stopped = true;
}
void create_cert_if_not_exists(const std::string& filename)
{
if (boost::filesystem::exists(filename))
return;
czmqpp::certificate cert = czmqpp::new_cert();
cert.save(filename);
log_info() << "Created new certificate file named " << filename;
log_info() << "Public key: " << cert.public_text();
}
void keep_pushing_count(broadcaster& brc)
{
// Create ZMQ socket.
czmqpp::context ctx;
BITCOIN_ASSERT(ctx.self());
czmqpp::authenticator auth(ctx);
#ifdef ONLY_LOCALHOST_CONNECTIONS
auth.allow("127.0.0.1");
#endif
czmqpp::socket socket(ctx, ZMQ_PUB);
BITCOIN_ASSERT(socket.self());
int bind_rc = socket.bind(
listen_transport(publish_connections_count_port));
BITCOIN_ASSERT(bind_rc != -1);
while (true)
{
czmqpp::message msg;
const auto data = bc::to_little_endian(brc.total_connections());
msg.append(bc::to_data_chunk(data));
// Send it.
bool rc = msg.send(socket);
BITCOIN_ASSERT(rc);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
}
void send_error_message(const bc::hash_digest& tx_hash, const std::string& err);
int main(int argc, char** argv)
{
// Used for casting the char** string to std::string.
auto is_help = [](const std::string arg)
{
return arg == "-h" || arg == "--help";
};
if (argc > 1 && is_help(argv[1]))
{
log_info() << "Usage: brc [ZMQ_TRANSPORT] [CLIENT_CERTS_DIR]";
log_info() << "Example: brc tcp://*:8989";
log_info() << "An empty CLIENT_CERTS_DIR will accept all certificates.";
log_info() << "See ZMQ manual for more info.";
return 0;
}
if (argc > 3)
{
log_fatal() << "brc: Too many arguments.";
return -1;
}
std::string zmq_transport = listen_transport(push_transaction_port);
std::string client_certs_dir;
if (argc == 2)
zmq_transport = argv[1];
if (argc == 3)
client_certs_dir = argv[2];
// libbitcoin stuff
broadcaster brc;
std::promise<std::error_code> ec_promise;
auto broadcaster_started =
[&ec_promise](const std::error_code& ec)
{
ec_promise.set_value(ec);
};
brc.start(4, target_connections, broadcaster_started);
std::error_code ec = ec_promise.get_future().get();
if (ec)
{
log_fatal() << "Problem starting broadcaster: " << ec.message();
brc.stop();
return -1;
}
log_info() << "Node started.";
// TODO: BUG handler doesn't get called.
signal(SIGINT, interrupt_handler);
// ZMQ stuff
czmqpp::context ctx;
BITCOIN_ASSERT(ctx.self());
// Start the authenticator and tell it do authenticate clients
// via the certificates stored in the .curve directory.
czmqpp::authenticator auth(ctx);
auth.set_verbose(true);
#ifdef ONLY_LOCALHOST_CONNECTIONS
auth.allow("127.0.0.1");
#endif
#ifdef CRYPTO_ENABLED
if (client_certs_dir.empty())
auth.configure_curve("*", CURVE_ALLOW_ANY);
else
auth.configure_curve("*", client_certs_dir);
create_cert_if_not_exists(server_cert_filename);
czmqpp::certificate server_cert =
czmqpp::load_cert(server_cert_filename);
#endif
// Create socket.
czmqpp::socket server(ctx, ZMQ_REP);
BITCOIN_ASSERT(server.self());
server.set_linger(0);
#ifdef CRYPTO_ENABLED
server_cert.apply(server);
server.set_curve_server(1);
#else
server.set_zap_domain("global");
#endif
int rc = server.bind(zmq_transport);
if (rc == -1)
{
log_fatal() << "Error initializing ZMQ socket: "
<< zmq_strerror(zmq_errno());
brc.stop();
return -1;
}
czmqpp::poller poller(server);
BITCOIN_ASSERT(poller.self());
// Thread which keeps publishing the connection count.
std::thread thread([&brc]() { keep_pushing_count(brc); });
while (!stopped)
{
czmqpp::socket sock = poller.wait(poll_sleep_interval);
if (!sock.self())
continue;
// Receive message.
czmqpp::message msg;
msg.receive(sock);
BITCOIN_ASSERT(msg.parts().size() == 1);
const bc::data_chunk& raw_tx = msg.parts()[0];
bool success = brc.broadcast(raw_tx);
if (!success)
log_warning() << "Invalid Tx received: "
<< bc::encode_base16(raw_tx);
// Respond back.
czmqpp::message response_msg;
// If successful respond with 0x01, otherwise return 0x00
constexpr uint8_t response_true = 0x01;
constexpr uint8_t response_false = 0x00;
czmqpp::data_chunk response{{
success ? response_true : response_false}};
response_msg.append(response);
bool rc = response_msg.send(sock);
BITCOIN_ASSERT(rc);
}
thread.detach();
brc.stop();
return 0;
}