openethereum/parity-clib/examples/cpp/main.cpp

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;
}