Scorum
api.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include <cctype>
25 
26 #include <scorum/app/api.hpp>
29 
31 
37 #include <fc/time.hpp>
38 
39 #include <graphene/utilities/key_conversion.hpp>
40 
41 #include <fc/crypto/hex.hpp>
42 #include <fc/smart_ref_impl.hpp>
43 
44 #include <graphene/utilities/git_revision.hpp>
45 #include <fc/git_revision.hpp>
46 
47 namespace scorum {
48 namespace app {
49 
51  : _ctx(ctx)
52 {
53 }
54 
56 {
57 }
58 
60 {
61 }
62 
63 bool login_api::login(const std::string& user, const std::string& password)
64 {
65  idump((user)(password));
66  optional<api_access_info> acc = _ctx.app.get_api_access_info(user);
67  if (!acc.valid())
68  return false;
69  if (acc->password_hash_b64 != "*")
70  {
71  std::string password_salt = fc::base64_decode(acc->password_salt_b64);
72  std::string acc_password_hash = fc::base64_decode(acc->password_hash_b64);
73 
74  fc::sha256 hash_obj = fc::sha256::hash(password + password_salt);
75  if (hash_obj.data_size() != acc_password_hash.length())
76  return false;
77  if (memcmp(hash_obj.data(), acc_password_hash.c_str(), hash_obj.data_size()) != 0)
78  return false;
79  }
80 
81  idump((acc->allowed_apis));
82  std::shared_ptr<api_session_data> session = _ctx.session.lock();
83  FC_ASSERT(session);
84 
85  std::map<std::string, fc::api_ptr>& _api_map = session->api_map;
86 
87  for (const std::string& api_name : acc->allowed_apis)
88  {
89  auto it = _api_map.find(api_name);
90  if (it != _api_map.end())
91  {
92  wlog("known api: ${api}", ("api", api_name));
93  continue;
94  }
95  idump((api_name));
96  api_context new_ctx(_ctx.app, api_name, _ctx.session);
97  _api_map[api_name] = _ctx.app.create_api_by_name(new_ctx);
98  }
99  return true;
100 }
101 
102 fc::api_ptr login_api::get_api_by_name(const std::string& api_name) const
103 {
104  std::shared_ptr<api_session_data> session = _ctx.session.lock();
105  FC_ASSERT(session);
106 
107  const std::map<std::string, fc::api_ptr>& _api_map = session->api_map;
108  auto it = _api_map.find(api_name);
109  if (it == _api_map.end())
110  {
111  wlog("unknown api: ${api}", ("api", api_name));
112  return fc::api_ptr();
113  }
114  if (it->second)
115  {
116  ilog("found api: ${api}", ("api", api_name));
117  }
118  FC_ASSERT(it->second != nullptr);
119  return it->second;
120 }
121 
123 {
124  return scorum_version_info(fc::string(SCORUM_BLOCKCHAIN_VERSION), fc::string(graphene::utilities::git_revision_sha),
125  fc::string(fc::git_revision_sha));
126 }
127 
129  : _app(a.app)
130 {
132  _app.get_max_block_age(_max_block_age);
133 }
134 
136 {
139  _applied_block_connection
141 }
142 
144 {
145  return _app.chain_database()->with_read_lock([&]() {
146  if (max_block_age < 0)
147  return false;
148 
149  fc::time_point_sec now = fc::time_point::now();
150  std::shared_ptr<database> db = _app.chain_database();
151  const dynamic_global_property_object& dgpo = db->obtain_service<dbs_dynamic_global_property>().get();
152 
153  return (dgpo.time < now - fc::seconds(max_block_age));
154  });
155 }
156 
157 void network_broadcast_api::set_max_block_age(int32_t max_block_age)
158 {
159  _max_block_age = max_block_age;
160 }
161 
163 {
165  auto capture_this = shared_from_this();
166 
167  fc::async([this, capture_this, b]() {
168  int32_t block_num = int32_t(b.block_num());
169  if (_callbacks.size())
170  {
171  for (size_t trx_num = 0; trx_num < b.transactions.size(); ++trx_num)
172  {
173  const auto& trx = b.transactions[trx_num];
174  auto id = trx.id();
175  auto itr = _callbacks.find(id);
176  if (itr == _callbacks.end())
177  continue;
178  confirmation_callback callback = itr->second;
179  itr->second = [](variant) {};
180  callback(fc::variant(transaction_confirmation(id, block_num, int32_t(trx_num), false)));
181  }
182  }
183 
185  while (true)
186  {
187  auto exp_it = _callbacks_expirations.begin();
188  if (exp_it == _callbacks_expirations.end())
189  break;
190  if (exp_it->first >= b.timestamp)
191  break;
192  for (const transaction_id_type& txid : exp_it->second)
193  {
194  auto cb_it = _callbacks.find(txid);
195  // If it's empty, that means the transaction has been confirmed and has been deleted by the above check.
196  if (cb_it == _callbacks.end())
197  continue;
198 
199  confirmation_callback callback = cb_it->second;
200  transaction_id_type txid_byval = txid; // can't pass in by reference as it's going to be deleted
201  callback(fc::variant(transaction_confirmation{ txid_byval, block_num, -1, true }));
202 
203  _callbacks.erase(cb_it);
204  }
205  _callbacks_expirations.erase(exp_it);
206  }
207  });
208 }
209 
211 {
212  trx.validate();
213 
214  if (_app.is_read_only())
215  {
216  _app.get_write_node_net_api()->broadcast_transaction(trx);
217  }
218  else
219  {
220  FC_ASSERT(!check_max_block_age(_max_block_age));
221  _app.chain_database()->push_transaction(trx);
222  _app.p2p_node()->broadcast_transaction(trx);
223  }
224 }
225 
227 {
228  if (_app.is_read_only())
229  {
230  return _app.get_write_node_net_api()->broadcast_transaction_synchronous(trx);
231  }
232  else
233  {
234  fc::promise<fc::variant>::ptr prom(new fc::promise<fc::variant>());
235  broadcast_transaction_with_callback([=](const fc::variant& v) { prom->set_value(v); }, trx);
236  return fc::future<fc::variant>(prom).wait();
237  }
238 }
239 
241 {
242  if (_app.is_read_only())
243  {
244  _app.get_write_node_net_api()->broadcast_block(b);
245  }
246  else
247  {
248  _app.chain_database()->push_block(b);
249  _app.p2p_node()->broadcast(graphene::net::block_message(b));
250  }
251 }
252 
254 {
255 public:
257  : _hardfork_svc(hardfork_svc)
258  {
259  }
260 
261  // available by default
262  template <typename Op> bool operator()(const Op&) const
263  {
264  return true;
265  }
266 
268  {
269  using namespace scorum::protocol;
270  // clang-format off
271  auto idx = op.operation.which();
272  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4)
273  || (idx != proposal_operation::tag<development_committee_empower_betting_moderator_operation>::value
274  && idx != proposal_operation::tag<development_committee_change_betting_resolve_delay_operation>::value);
275  // clang-format on
276  }
277 
279  {
280  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4);
281  }
282 
284  {
285  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4);
286  }
287 
289  {
290  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4);
291  }
292 
294  {
295  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4);
296  }
297 
299  {
300  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4);
301  }
302 
304  {
305  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4);
306  }
307 
309  {
310  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4);
311  }
312 
314  {
315  return _hardfork_svc.has_hardfork(SCORUM_HARDFORK_0_4);
316  }
317 
318 private:
319  hardfork_property_service_i& _hardfork_svc;
320 };
321 
323 {
324  if (_app.is_read_only())
325  {
326  _app.get_write_node_net_api()->broadcast_transaction_with_callback(cb, trx);
327  }
328  else
329  {
330  FC_ASSERT(!check_max_block_age(_max_block_age));
331  auto& hardfork_svc = _app.chain_database()->hardfork_property_service();
332  for (const auto& op : trx.operations)
333  {
334  FC_ASSERT(op.visit(check_banned_operations_visitor(hardfork_svc)), "Operation ${op} is locked.",
335  ("op", op));
336  }
337  trx.validate();
338  _callbacks[trx.id()] = cb;
339  _callbacks_expirations[trx.expiration].push_back(trx.id());
340 
341  _app.chain_database()->push_transaction(trx);
342  _app.p2p_node()->broadcast_transaction(trx);
343  }
344 }
345 
347  : _app(a.app)
348 {
349 }
350 
352 {
353 }
354 
355 fc::variant_object network_node_api::get_info() const
356 {
357  fc::mutable_variant_object result = _app.p2p_node()->network_get_info();
358  result["connection_count"] = _app.p2p_node()->get_connection_count();
359  return result;
360 }
361 
362 void network_node_api::add_node(const fc::ip::endpoint& ep)
363 {
364  _app.p2p_node()->add_node(ep);
365 }
366 
367 std::vector<graphene::net::peer_status> network_node_api::get_connected_peers() const
368 {
369  return _app.p2p_node()->get_connected_peers();
370 }
371 
372 std::vector<graphene::net::potential_peer_record> network_node_api::get_potential_peers() const
373 {
374  return _app.p2p_node()->get_potential_peers();
375 }
376 
378 {
379  return _app.p2p_node()->get_advanced_node_parameters();
380 }
381 
382 void network_node_api::set_advanced_node_parameters(const fc::variant_object& params)
383 {
384  return _app.p2p_node()->set_advanced_node_parameters(params);
385 }
386 }
387 } // scorum::app
std::shared_ptr< chain::database > chain_database() const
graphene::net::node_ptr p2p_node()
fc::api< network_broadcast_api > & get_write_node_net_api()
fc::optional< api_access_info > get_api_access_info(const std::string &username) const
fc::api_ptr create_api_by_name(const api_context &ctx)
void get_max_block_age(int32_t &result)
bool operator()(const scorum::protocol::cancel_pending_bets_operation &) const
Definition: api.cpp:278
bool operator()(const scorum::protocol::update_game_markets_operation &) const
Definition: api.cpp:293
bool operator()(const scorum::protocol::post_bet_operation &) const
Definition: api.cpp:308
check_banned_operations_visitor(hardfork_property_service_i &hardfork_svc)
Definition: api.cpp:256
bool operator()(const scorum::protocol::proposal_create_operation &op) const
Definition: api.cpp:267
bool operator()(const scorum::protocol::delegate_sp_from_reg_pool_operation &) const
Definition: api.cpp:313
bool operator()(const scorum::protocol::post_game_results_operation &) const
Definition: api.cpp:303
bool operator()(const Op &) const
Definition: api.cpp:262
bool operator()(const scorum::protocol::update_game_start_time_operation &) const
Definition: api.cpp:298
bool operator()(const scorum::protocol::cancel_game_operation &) const
Definition: api.cpp:288
bool operator()(const scorum::protocol::create_game_operation &) const
Definition: api.cpp:283
virtual ~login_api()
Definition: api.cpp:55
scorum_version_info get_version()
Definition: api.cpp:122
bool login(const std::string &user, const std::string &password)
Authenticate to the RPC server.
Definition: api.cpp:63
fc::api_ptr get_api_by_name(const std::string &api_name) const
Definition: api.cpp:102
login_api(const api_context &ctx)
Definition: api.cpp:50
void on_api_startup()
internal method, not exposed via JSON RPC
Definition: api.cpp:59
fc::variant broadcast_transaction_synchronous(const signed_transaction &trx)
Definition: api.cpp:226
void broadcast_transaction_with_callback(confirmation_callback cb, const signed_transaction &trx)
Definition: api.cpp:322
bool check_max_block_age(int32_t max_block_age)
Definition: api.cpp:143
void broadcast_transaction(const signed_transaction &trx)
Broadcast a transaction to the network.
Definition: api.cpp:210
std::function< void(variant)> confirmation_callback
Definition: api.hpp:76
network_broadcast_api(const api_context &a)
Definition: api.cpp:128
void on_api_startup()
internal method, not exposed via JSON RPC
Definition: api.cpp:135
void on_applied_block(const signed_block &b)
Not reflected, thus not accessible to API clients.
Definition: api.cpp:162
void broadcast_block(const signed_block &block)
Definition: api.cpp:240
void set_max_block_age(int32_t max_block_age)
Definition: api.cpp:157
void add_node(const fc::ip::endpoint &ep)
add_node Connect to a new peer
Definition: api.cpp:362
std::vector< graphene::net::potential_peer_record > get_potential_peers() const
Return list of potential peers.
Definition: api.cpp:372
fc::variant_object get_advanced_node_parameters() const
Get advanced node parameters, such as desired and max number of connections.
Definition: api.cpp:377
void on_api_startup()
internal method, not exposed via JSON RPC
Definition: api.cpp:351
std::vector< graphene::net::peer_status > get_connected_peers() const
Get status of all current connections to peers.
Definition: api.cpp:367
network_node_api(const api_context &a)
Definition: api.cpp:346
void set_advanced_node_parameters(const fc::variant_object &params)
Set advanced node parameters, such as desired and max number of connections.
Definition: api.cpp:382
fc::variant_object get_info() const
Return general network information, such as p2p port.
Definition: api.cpp:355
#define SCORUM_BLOCKCHAIN_VERSION
Definition: config.hpp:91
boost::signals2::scoped_connection connect_signal(boost::signals2::signal< void(Args...)> &sig, C &c, void(C::*f)(Args...))
fc::ripemd160 transaction_id_type
Definition: types.hpp:65
Definition: asset.cpp:15
std::weak_ptr< api_session_data > session
Definition: api_context.hpp:42
virtual bool has_hardfork(uint32_t hardfork) const =0
fc::time_point_sec timestamp
This operation cancel unmatched bets by id.
This operation creates game object.
With this operation moderator provides game results(wincases)
std::vector< signed_transaction > transactions
Definition: block.hpp:13
transaction_id_type id() const
Definition: transaction.cpp:43
std::vector< operation > operations
Definition: transaction.hpp:18
fc::time_point_sec expiration
Definition: transaction.hpp:16
This operation updates game markets list.
This operation updates game start time.