Electroneum
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 
34 using namespace epee;
35 
36 namespace tools
37 {
38 
39 static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
40 
41 NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::recursive_mutex &mutex)
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 
64 boost::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 
89 boost::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 
114 boost::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 
123 boost::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 
132 boost::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 
141 boost::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 
164 boost::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 
196 boost::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 }
const char * res
Definition: hmac_keccak.cpp:41
#define MERROR(x)
Definition: misc_log_ex.h:73
boost::optional< std::string > get_earliest_height(uint8_t version, uint64_t &earliest_height) const
::std::string string
Definition: gtest-port.h:1097
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
uint64_t height
Definition: blockchain.cpp:91
#define CORE_RPC_STATUS_BUSY
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")
unsigned char uint8_t
Definition: stdint.h:124
#define CORE_RPC_STATUS_OK
time_t time
Definition: blockchain.cpp:93
unsigned int uint32_t
Definition: stdint.h:126
Various Tools.
Definition: tools.cpp:31
unsigned __int64 uint64_t
Definition: stdint.h:136
#define false
Definition: stdbool.h:38
boost::optional< std::string > get_block_weight_limit(uint64_t &block_weight_limit) const
version
Supported socks variants.
Definition: socks.h:57
boost::optional< std::string > get_fee_quantization_mask(uint64_t &fee_quantization_mask) const
boost::optional< std::string > get_target_height(uint64_t &height) const
void set_height(uint64_t h)
#define AUTO_VAL_INIT(v)
Definition: misc_language.h:53
boost::optional< std::string > get_height(uint64_t &height) const
boost::optional< std::string > get_rpc_version(uint32_t &version) const
boost::optional< std::string > get_dynamic_base_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const