Electroneum
Loading...
Searching...
No Matches
node_rpc_proxy.cpp
Go to the documentation of this file.
1// Copyright (c) 2017-Present, Electroneum
2// Copyright (c) 2017-2019, The Monero Project
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without modification, are
7// permitted provided that the following conditions are met:
8//
9// 1. Redistributions of source code must retain the above copyright notice, this list of
10// conditions and the following disclaimer.
11//
12// 2. Redistributions in binary form must reproduce the above copyright notice, this list
13// of conditions and the following disclaimer in the documentation and/or other
14// materials provided with the distribution.
15//
16// 3. Neither the name of the copyright holder nor the names of its contributors may be
17// used to endorse or promote products derived from this software without specific
18// prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "node_rpc_proxy.h"
33
34using namespace epee;
35
36namespace tools
37{
38
39static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
40
42 : m_http_client(http_client)
43 , m_daemon_rpc_mutex(mutex)
44 , m_offline(false)
45{
46 invalidate();
47}
48
50{
51 m_height = 0;
52 for (size_t n = 0; n < 256; ++n)
53 m_earliest_height[n] = 0;
54 m_dynamic_base_fee_estimate = 0;
55 m_dynamic_base_fee_estimate_cached_height = 0;
56 m_dynamic_base_fee_estimate_grace_blocks = 0;
57 m_fee_quantization_mask = 1;
58 m_rpc_version = 0;
59 m_target_height = 0;
60 m_block_weight_limit = 0;
61 m_get_info_time = 0;
62}
63
64boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const
65{
66 if (m_offline)
67 return boost::optional<std::string>("offline");
68 if (m_rpc_version == 0)
69 {
72 m_daemon_rpc_mutex.lock();
73 bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_version", req_t, resp_t, m_http_client, rpc_timeout);
74 m_daemon_rpc_mutex.unlock();
75 CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon");
76 CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
77 CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get daemon RPC version");
78 m_rpc_version = resp_t.version;
79 }
80 rpc_version = m_rpc_version;
81 return boost::optional<std::string>();
82}
83
85{
86 m_height = h;
87}
88
89boost::optional<std::string> NodeRPCProxy::get_info() const
90{
91 if (m_offline)
92 return boost::optional<std::string>("offline");
93 const time_t now = time(NULL);
94 if (now >= m_get_info_time + 30) // re-cache every 30 seconds
95 {
98
99 m_daemon_rpc_mutex.lock();
100 bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_info", req_t, resp_t, m_http_client, rpc_timeout);
101 m_daemon_rpc_mutex.unlock();
102
103 CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon");
104 CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
105 CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get target blockchain height");
106 m_height = resp_t.height;
107 m_target_height = resp_t.target_height;
108 m_block_weight_limit = resp_t.block_weight_limit ? resp_t.block_weight_limit : resp_t.block_size_limit;
109 m_get_info_time = now;
110 }
111 return boost::optional<std::string>();
112}
113
114boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) const
115{
116 auto res = get_info();
117 if (res)
118 return res;
119 height = m_height;
120 return boost::optional<std::string>();
121}
122
123boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) const
124{
125 auto res = get_info();
126 if (res)
127 return res;
128 height = m_target_height;
129 return boost::optional<std::string>();
130}
131
132boost::optional<std::string> NodeRPCProxy::get_block_weight_limit(uint64_t &block_weight_limit) const
133{
134 auto res = get_info();
135 if (res)
136 return res;
137 block_weight_limit = m_block_weight_limit;
138 return boost::optional<std::string>();
139}
140
141boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const
142{
143 if (m_offline)
144 return boost::optional<std::string>("offline");
145 if (m_earliest_height[version] == 0)
146 {
149
150 m_daemon_rpc_mutex.lock();
151 req_t.version = version;
152 bool r = net_utils::invoke_http_json_rpc("/json_rpc", "hard_fork_info", req_t, resp_t, m_http_client, rpc_timeout);
153 m_daemon_rpc_mutex.unlock();
154 CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon");
155 CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
156 CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get hard fork status");
157 m_earliest_height[version] = resp_t.earliest_height;
158 }
159
160 earliest_height = m_earliest_height[version];
161 return boost::optional<std::string>();
162}
163
164boost::optional<std::string> NodeRPCProxy::get_dynamic_base_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const
165{
167
168 boost::optional<std::string> result = get_height(height);
169 if (result)
170 return result;
171
172 if (m_offline)
173 return boost::optional<std::string>("offline");
174 if (m_dynamic_base_fee_estimate_cached_height != height || m_dynamic_base_fee_estimate_grace_blocks != grace_blocks)
175 {
178
179 m_daemon_rpc_mutex.lock();
180 req_t.grace_blocks = grace_blocks;
181 bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_fee_estimate", req_t, resp_t, m_http_client, rpc_timeout);
182 m_daemon_rpc_mutex.unlock();
183 CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon");
184 CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
185 CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get fee estimate");
186 m_dynamic_base_fee_estimate = resp_t.fee;
187 m_dynamic_base_fee_estimate_cached_height = height;
188 m_dynamic_base_fee_estimate_grace_blocks = grace_blocks;
189 m_fee_quantization_mask = resp_t.quantization_mask;
190 }
191
192 fee = m_dynamic_base_fee_estimate;
193 return boost::optional<std::string>();
194}
195
196boost::optional<std::string> NodeRPCProxy::get_fee_quantization_mask(uint64_t &fee_quantization_mask) const
197{
199
200 boost::optional<std::string> result = get_height(height);
201 if (result)
202 return result;
203
204 if (m_offline)
205 return boost::optional<std::string>("offline");
206 if (m_dynamic_base_fee_estimate_cached_height != height)
207 {
210
211 m_daemon_rpc_mutex.lock();
212 req_t.grace_blocks = m_dynamic_base_fee_estimate_grace_blocks;
213 bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_fee_estimate", req_t, resp_t, m_http_client, rpc_timeout);
214 m_daemon_rpc_mutex.unlock();
215 CHECK_AND_ASSERT_MES(r, std::string("Failed to connect to daemon"), "Failed to connect to daemon");
216 CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
217 CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get fee estimate");
218 m_dynamic_base_fee_estimate = resp_t.fee;
219 m_dynamic_base_fee_estimate_cached_height = height;
220 m_fee_quantization_mask = resp_t.quantization_mask;
221 }
222
223 fee_quantization_mask = m_fee_quantization_mask;
224 if (fee_quantization_mask == 0)
225 {
226 MERROR("Fee quantization mask is 0, forcing to 1");
227 fee_quantization_mask = 1;
228 }
229 return boost::optional<std::string>();
230}
231
232}
uint64_t height
uint8_t version
time_t time
boost::optional< std::string > get_target_height(uint64_t &height) const
boost::optional< std::string > get_rpc_version(uint32_t &version) const
boost::optional< std::string > get_earliest_height(uint8_t version, uint64_t &earliest_height) const
boost::optional< std::string > get_fee_quantization_mask(uint64_t &fee_quantization_mask) const
void set_height(uint64_t h)
boost::optional< std::string > get_height(uint64_t &height) const
boost::optional< std::string > get_dynamic_base_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const
boost::optional< std::string > get_block_weight_limit(uint64_t &block_weight_limit) const
NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::recursive_mutex &mutex)
#define CORE_RPC_STATUS_OK
#define CORE_RPC_STATUS_BUSY
const char * res
#define AUTO_VAL_INIT(v)
#define MERROR(x)
Definition misc_log_ex.h:73
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
http_simple_client_template< blocked_mode_client > http_simple_client
bool invoke_http_json_rpc(const boost::string_ref uri, std::string method_name, const t_request &out_struct, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref http_method="GET", const std::string &req_id="0")
Various Tools.
Definition tools.cpp:31
#define false
unsigned int uint32_t
Definition stdint.h:126
unsigned char uint8_t
Definition stdint.h:124
unsigned __int64 uint64_t
Definition stdint.h:136
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request
epee::misc_utils::struct_init< response_t > response
epee::misc_utils::struct_init< request_t > request