0f9b2218da
* prevent silent errors in daemon mode * change author in Cargo.toml, add preamble to pipe.rs * set the uid and gid on daemon process, fix permission errors when writing to pid file * call setup_logger before daemonize to prevent crashing when attempting to create logfile * map_err for calls to splice and ioctl, fix spaces in Cargo.toml * split out daemonize to own repo * removed util/daemonize * renamed dep to parity-daemonize * fix(parity-clib): enable `logger` * bump parity-daemonize * remove obsolete comment Co-Authored-By: seunlanlege <seunlanlege@gmail.com> * fix(grumbles): docs and log in ParityParams * Add FIXME comment regarding @tomaka grumbles * Unify logger with the C-API in ParityParams (less type-safety with more from_raw() conversions) * Add better documentation in the `parity.h` * Apply suggestions from code review Co-Authored-By: seunlanlege <seunlanlege@gmail.com> * docs(parity lib): add link to logging issue * fix(parity-clib): JNI enable `logger` * fix(parity-clib): update `Java example` * Update example to the API changes * Remove needless printouts which can be controlled via logger instead
186 lines
5.2 KiB
C++
186 lines
5.2 KiB
C++
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
|
// This file is part of Parity Ethereum.
|
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include <chrono>
|
|
#include <parity.h>
|
|
#include <regex>
|
|
#include <string>
|
|
#include <thread>
|
|
|
|
void* parity_run(std::vector<const char*>);
|
|
int parity_subscribe_to_websocket(void*);
|
|
int parity_rpc_queries(void*);
|
|
|
|
const int SUBSCRIPTION_ID_LEN = 18;
|
|
const size_t TIMEOUT_ONE_MIN_AS_MILLIS = 60 * 1000;
|
|
const unsigned int CALLBACK_RPC = 1;
|
|
const unsigned int CALLBACK_WS = 2;
|
|
|
|
struct Callback {
|
|
unsigned int type;
|
|
long unsigned int counter;
|
|
};
|
|
|
|
// list of rpc queries
|
|
const std::vector<std::string> rpc_queries {
|
|
"{\"method\":\"parity_versionInfo\",\"params\":[],\"id\":1,\"jsonrpc\":\"2.0\"}",
|
|
"{\"method\":\"eth_getTransactionReceipt\",\"params\":[\"0x444172bef57ad978655171a8af2cfd89baa02a97fcb773067aef7794d6913fff\"],\"id\":1,\"jsonrpc\":\"2.0\"}",
|
|
"{\"method\":\"eth_estimateGas\",\"params\":[{\"from\":\"0x0066Dc48bb833d2B59f730F33952B3c29fE926F5\"}],\"id\":1,\"jsonrpc\":\"2.0\"}",
|
|
"{\"method\":\"eth_getBalance\",\"params\":[\"0x0066Dc48bb833d2B59f730F33952B3c29fE926F5\"],\"id\":1,\"jsonrpc\":\"2.0\"}"
|
|
};
|
|
|
|
// list of subscriptions
|
|
const std::vector<std::string> ws_subscriptions {
|
|
"{\"method\":\"parity_subscribe\",\"params\":[\"eth_getBalance\",[\"0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826\",\"latest\"]],\"id\":1,\"jsonrpc\":\"2.0\"}",
|
|
"{\"method\":\"parity_subscribe\",\"params\":[\"parity_netPeers\"],\"id\":1,\"jsonrpc\":\"2.0\"}",
|
|
"{\"method\":\"eth_subscribe\",\"params\":[\"newHeads\"],\"id\":1,\"jsonrpc\":\"2.0\"}"
|
|
};
|
|
|
|
// callback that gets invoked upon an event
|
|
void callback(void* user_data, const char* response, size_t _len) {
|
|
Callback* cb = static_cast<Callback*>(user_data);
|
|
if (cb->type == CALLBACK_RPC) {
|
|
cb->counter -= 1;
|
|
} else if (cb->type == CALLBACK_WS) {
|
|
std::regex is_subscription ("\\{\"jsonrpc\":\"2.0\",\"result\":\"0[xX][a-fA-F0-9]{16}\",\"id\":1\\}");
|
|
if (std::regex_match(response, is_subscription) == true) {
|
|
cb->counter -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
// run full-client
|
|
{
|
|
std::vector<const char*> config = {"--no-ipc" , "--jsonrpc-apis=all", "--chain", "kovan"};
|
|
void* parity = parity_run(config);
|
|
if (parity_rpc_queries(parity)) {
|
|
printf("rpc_queries failed\r\n");
|
|
return 1;
|
|
}
|
|
|
|
if (parity_subscribe_to_websocket(parity)) {
|
|
printf("ws_queries failed\r\n");
|
|
return 1;
|
|
}
|
|
|
|
if (parity != nullptr) {
|
|
parity_destroy(parity);
|
|
}
|
|
}
|
|
|
|
// run light-client
|
|
{
|
|
std::vector<const char*> light_config = {"--no-ipc", "--light", "--jsonrpc-apis=all", "--chain", "kovan"};
|
|
void* parity = parity_run(light_config);
|
|
|
|
if (parity_rpc_queries(parity)) {
|
|
printf("rpc_queries failed\r\n");
|
|
return 1;
|
|
}
|
|
|
|
if (parity_subscribe_to_websocket(parity)) {
|
|
printf("ws_queries failed\r\n");
|
|
return 1;
|
|
}
|
|
|
|
if (parity != nullptr) {
|
|
parity_destroy(parity);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int parity_rpc_queries(void* parity) {
|
|
if (!parity) {
|
|
return 1;
|
|
}
|
|
|
|
Callback cb { .type = CALLBACK_RPC, .counter = rpc_queries.size() };
|
|
|
|
for (auto query : rpc_queries) {
|
|
if (parity_rpc(parity, query.c_str(), query.length(), TIMEOUT_ONE_MIN_AS_MILLIS, callback, &cb) != 0) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
while(cb.counter != 0);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int parity_subscribe_to_websocket(void* parity) {
|
|
if (!parity) {
|
|
return 1;
|
|
}
|
|
|
|
std::vector<const void*> sessions;
|
|
|
|
Callback cb { .type = CALLBACK_WS, .counter = ws_subscriptions.size() };
|
|
|
|
for (auto sub : ws_subscriptions) {
|
|
void *const session = parity_subscribe_ws(parity, sub.c_str(), sub.length(), callback, &cb);
|
|
if (!session) {
|
|
return 1;
|
|
}
|
|
sessions.push_back(session);
|
|
}
|
|
|
|
while(cb.counter != 0);
|
|
std::this_thread::sleep_for(std::chrono::seconds(60));
|
|
for (auto session : sessions) {
|
|
parity_unsubscribe_ws(session);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void* parity_run(std::vector<const char*> args) {
|
|
ParityParams cfg = {
|
|
.configuration = nullptr,
|
|
.on_client_restart_cb = callback,
|
|
.on_client_restart_cb_custom = nullptr,
|
|
.logger = nullptr
|
|
};
|
|
|
|
std::vector<size_t> str_lens;
|
|
|
|
for (auto arg: args) {
|
|
str_lens.push_back(std::strlen(arg));
|
|
}
|
|
|
|
// make sure no out-of-range access happens here
|
|
if (args.empty()) {
|
|
if (parity_config_from_cli(nullptr, nullptr, 0, &cfg.configuration) != 0) {
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
if (parity_config_from_cli(&args[0], &str_lens[0], args.size(), &cfg.configuration) != 0) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// enable logging but only the `rpc module` and don't write it to a file
|
|
char log_mode [] = "rpc=trace";
|
|
parity_set_logger(log_mode, strlen(log_mode), nullptr, 0, &cfg.logger);
|
|
|
|
void *parity = nullptr;
|
|
if (parity_start(&cfg, &parity) != 0) {
|
|
return nullptr;
|
|
}
|
|
|
|
return parity;
|
|
}
|