// 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 . #include #include #include #include #include void* parity_run(std::vector); 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 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 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(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 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 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 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 args) { ParityParams cfg = { .configuration = nullptr, .on_client_restart_cb = callback, .on_client_restart_cb_custom = nullptr, .logger = nullptr }; std::vector 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; }