Electroneum
validators.h
Go to the documentation of this file.
1 // Copyrights(c) 2017-2021, The Electroneum Project
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification, are
6 // permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice, this list of
9 // conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 // of conditions and the following disclaimer in the documentation and/or other
13 // materials provided with the distribution.
14 //
15 // 3. Neither the name of the copyright holder nor the names of its contributors may be
16 // used to endorse or promote products derived from this software without specific
17 // prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 
30 #ifndef ELECTRONEUM_VALIDATORS_H
31 #define ELECTRONEUM_VALIDATORS_H
32 
33 #include <boost/algorithm/hex.hpp>
34 
36 #include "include_base_utils.h"
37 #include "net/http_client.h"
40 #include "crypto/crypto.h"
42 #include "math_helper.h"
44 
45 namespace electroneum {
46  namespace basic {
47  using namespace std;
48  using namespace std::chrono;
49  using namespace boost::algorithm;
50  using namespace epee::math_helper;
51  using namespace epee::serialization;
52 
53  enum class ValidatorsState{
54  Valid,
56  Expired,
57  Invalid,
58  Disabled
59  };
60 
61  enum class list_update_outcome{
62  Success,
66  Old_List,
67  Same_List,
70  };
71 
72  class Validator {
73  private:
74  string publicKey;
75  uint64_t startHeight;
76  uint64_t endHeight;
77  string name;
78  string domain;
79  string page_link;
80  public:
81 
82  Validator();
83  Validator(const string &publicKey, uint64_t startHeight, uint64_t endHeight, string name = "", string domain = "", string page_link = "");
84 
85  inline const string getPublicKey() {
86  return this->publicKey;
87  }
88 
90  return this->startHeight;
91  }
92 
94  return this->endHeight;
95  }
96 
97  inline void setEndHeight(uint64_t end_height) {
98  this->endHeight = end_height;
99  }
100 
102  return height >= this->startHeight && (height <= this->endHeight || this->endHeight == 0);
103  }
104 
105  inline void setName(string name) {
106  this->name = name;
107  }
108 
109  inline string getName() {
110  return this->name;
111  }
112 
113  inline void setDomain(string domain) {
114  this->domain = domain;
115  }
116 
117  inline string getdomain() {
118  return this->domain;
119  }
120 
121  inline void setPageLink(string page_link) {
122  this->page_link = page_link;
123  }
124 
125  inline string getPageLink() {
126  return this->page_link;
127  }
128 
130  Validator v;
131  v.name = this->name;
132  v.domain = this->domain;
133  v.page_link = this->page_link;
134 
135  return v;
136  }
137  };
138 
139  class Validators {
140  private:
141  vector<std::unique_ptr<Validator>> list;
142  uint64_t current_list_timestamp;
144  string endpoint_addr = "vl.electroneum.com";
145  string endpoint_port = "80";
146  string testnet_endpoint_addr = "vl.thesecurityteam.rocks";
147  string testnet_endpoint_port = "80";
148  milliseconds endpoint_timeout = milliseconds(10000);
149  string serialized_v_list;
151  time_t last_updated;
152  uint32_t timeout = 60*60*12; //12 hours
153  uint32_t timeout_grace_period = this->timeout * 0.1; //10% of timeout
154  once_a_time_seconds<60, true> m_load_validators_interval;
156  bool testnet = false;
157 
159 
160  void add(const string &key, uint64_t startHeight, uint64_t endHeight, string name = "", string domain ="", string page_link = "");
161  void addOrUpdate(const string &key, uint64_t startHeight, uint64_t endHeight, string name = "", string domain ="", string page_link = "");
162  void update(const string &key, uint64_t endHeight, string name = "", string domain ="", string page_link = "");
163  std::unique_ptr<Validator> find(const string &key);
164  bool exists(const string &key);
165  list_update_outcome validate_and_update(v_list_struct res, bool saveToDB, bool isEmergencyUpdate = false);
166  ValidatorsState validate_expiration();
167 
168  public:
169  explicit Validators(cryptonote::BlockchainDB &db, cryptonote::i_cryptonote_protocol* pprotocol, bool testnet) : m_db(db), current_list_timestamp(0) {
170  testnet ? this->http_client.set_server(this->testnet_endpoint_addr, this->testnet_endpoint_port, boost::none) :
171  this->http_client.set_server(this->endpoint_addr, this->endpoint_port, boost::none);
172  this->testnet = testnet;
173  this->m_p2p = pprotocol;
174  };
175 
176  inline vector<string> getApplicablePublicKeys(uint64_t height, bool convert_to_byte = false) {
177  vector<string> keys;
178  all_of(this->list.begin(), this->list.end(), [&height, &keys, &convert_to_byte](std::unique_ptr<Validator> &v) {
179  if (v->isWithinRange(height)) {
180  const string k = convert_to_byte ? unhex(v->getPublicKey()) : v->getPublicKey();
181  keys.push_back(k);
182  }
183  return true;
184  });
185  return keys;
186  }
187 
188  inline Validator getValidatorByKey(string key) {
189  Validator result;
190  all_of(this->list.begin(), this->list.end(), [&key, &result](std::unique_ptr<Validator> &v) {
191  if (v->getPublicKey() == key) {
192  result = v->getValidatorInfo();
193  }
194  return true;
195  });
196  return result;
197  }
198 
199  inline bool loadValidatorsList() {
200 
203 
204  // Try fetching list of validators from JSON endpoint
205  if(this->status == ValidatorsState::Invalid || this->status == ValidatorsState::Expired || this->status == ValidatorsState::NeedsUpdate) {
206  if (!get_http_json("/", res, this->http_client)) {
207  LOG_PRINT_L1("Unable to get validator_list json from " << this->endpoint_addr << ":" << this->endpoint_port);
208  }
209 
210  this->timeout = 60*60*24;
211  list_update_outcome isJsonValid = validate_and_update(res, true);
212 
213  if(isJsonValid == list_update_outcome::Success || isJsonValid == list_update_outcome::Same_List) {
214  MGINFO("Validators list loaded from JSON endpoint! Refresh in 12 hours");
215  return true;
216  }
217 
218  //If the list was old, invalid, or had an invalid public key, try getting list of validators from peers
219  if(m_p2p->request_validators_list_to_all() && this->status == ValidatorsState::Valid) {
220  this->timeout = 60*60*1;
221  MGINFO("Validators list loaded from peers! Refresh in 1 hour");
222  return true;
223  }
224 
225  //Keep returning true during the grace period
226  if(this->status == ValidatorsState::NeedsUpdate) {
227  LOG_PRINT_L1("Validator List Grace Period");
228  return true;
229  }
230 
231  // If we there was an issue with getting the list from peers, try getting list of validators from db.
232  // This code will only be reached at the daemon start if both endpoint & p2p list are unavailable.
233  string v = m_db.get_validator_list();
234  if(!v.empty()) {
235  this->timeout = 60*60*1;
236  list_update_outcome isDBListValid = setValidatorsList(v, true);
238  MGINFO("Validators list loaded from database! Refresh in 1 hour");
239  return true;
240  }
241  }
242 
243 
244  return false;
245  }
246 
247  return true;
248  }
249 
250  inline string getSerializedValidatorList() {
251 
252  if(this->status == ValidatorsState::NeedsUpdate || this->status == ValidatorsState::Expired) {
253  return string("");
254  }
255 
256  return this->serialized_v_list;
257  }
258 
259  inline list_update_outcome setValidatorsList(const string &v_list, bool saveToDB, bool isEmergencyUpdate = false) {
261  load_t_from_json(res, v_list);
262 
263  return validate_and_update(res, saveToDB, isEmergencyUpdate);
264  }
265 
266  inline bool isValid() {
267  return this->status == ValidatorsState::Valid || this->status == ValidatorsState::NeedsUpdate;
268  }
269 
270  inline bool isEnabled() {
271  return this->status != ValidatorsState::Disabled;
272  }
273 
274  inline void enable() {
275  this->status = ValidatorsState::Expired;
276  }
277 
278  inline void on_idle() {
279  if(this->status != ValidatorsState::Disabled) {
280  if(validate_expiration() != ValidatorsState::Valid) {
281  m_load_validators_interval.do_call(boost::bind(&Validators::loadValidatorsList, this));
282  }
283  }
284  }
285  };
286  }
287 }
288 
289 #endif //ELECTRONEUM_VALIDATORS_H
const char * res
Definition: hmac_keccak.cpp:41
virtual bool request_validators_list_to_all()=0
vector< string > getApplicablePublicKeys(uint64_t height, bool convert_to_byte=false)
Definition: validators.h:176
bool set_server(const std::string &address, boost::optional< login > user, ssl_options_t ssl_options=ssl_support_t::e_ssl_support_autodetect)
Definition: http_client.h:302
bool isWithinRange(uint64_t height)
Definition: validators.h:101
void setPageLink(string page_link)
Definition: validators.h:121
std::string publicKey
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
::std::string string
Definition: gtest-port.h:1097
Validator getValidatorByKey(string key)
Definition: validators.h:188
uint64_t height
Definition: blockchain.cpp:91
const char * key
Definition: hmac_keccak.cpp:39
void setDomain(string domain)
Definition: validators.h:113
STL namespace.
const char * name
#define MGINFO(x)
Definition: misc_log_ex.h:80
const string getPublicKey()
Definition: validators.h:85
Validators(cryptonote::BlockchainDB &db, cryptonote::i_cryptonote_protocol *pprotocol, bool testnet)
Definition: validators.h:169
bool load_t_from_json(t_struct &out, const std::string &json_buff)
unsigned int uint32_t
Definition: stdint.h:126
void setEndHeight(uint64_t end_height)
Definition: validators.h:97
list_update_outcome setValidatorsList(const string &v_list, bool saveToDB, bool isEmergencyUpdate=false)
Definition: validators.h:259
unsigned __int64 uint64_t
Definition: stdint.h:136
The BlockchainDB backing store interface declaration/contract.
#define AUTO_VAL_INIT(v)
Definition: misc_language.h:53
virtual std::string get_validator_list() const =0
bool get_http_json(const boost::string_ref uri, t_response &result_struct, t_transport &transport, std::chrono::milliseconds timeout=std::chrono::seconds(15), const boost::string_ref method="GET")
void setName(string name)
Definition: validators.h:105
bool do_call(functor_t functr)
Definition: math_helper.h:263