Electroneum
validators.h
Go to the documentation of this file.
1 // Copyrights(c) 2017-2019, 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"
38 #include "storages/http_abstract_invoke.h"
39 #include "storages/portable_storage.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  public:
78 
79  Validator();
80  Validator(const string &publicKey, uint64_t startHeight, uint64_t endHeight);
81 
82  inline const string getPublicKey() {
83  return this->publicKey;
84  }
85 
86  inline const uint64_t getStartHeight() {
87  return this->startHeight;
88  }
89 
90  inline const uint64_t getEndHeight() {
91  return this->endHeight;
92  }
93 
94  inline void setEndHeight(uint64_t end_height) {
95  this->endHeight = end_height;
96  }
97 
98  inline bool isWithinRange(uint64_t height) {
99  return height >= this->startHeight && (height <= this->endHeight || this->endHeight == 0);
100  }
101  };
102 
103  class Validators {
104  private:
105  vector<std::unique_ptr<Validator>> list;
107  epee::net_utils::http::http_simple_client http_client;
108  string endpoint_addr = "vl.electroneum.com";
109  string endpoint_port = "80";
110  string testnet_endpoint_addr = "vl.thesecurityteam.rocks";
111  string testnet_endpoint_port = "80";
112  milliseconds endpoint_timeout = milliseconds(10000);
115  time_t last_updated;
116  uint32_t timeout = 60*60*12; //12 hours
117  uint32_t timeout_grace_period = this->timeout * 0.1; //10% of timeout
118  bool isInitial = true;
119  once_a_time_seconds<60, true> m_load_validators_interval;
121  bool testnet = false;
122 
124 
125  void add(const string &key, uint64_t startHeight, uint64_t endHeight);
126  void addOrUpdate(const string &key, uint64_t startHeight, uint64_t endHeight);
127  void update(const string &key, uint64_t endHeight);
128  std::unique_ptr<Validator> find(const string &key);
129  bool exists(const string &key);
130  list_update_outcome validate_and_update(v_list_struct res, bool saveToDB, bool isEmergencyUpdate = false);
131  ValidatorsState validate_expiration();
132 
133  public:
134  explicit Validators(cryptonote::BlockchainDB &db, cryptonote::i_cryptonote_protocol* pprotocol, bool testnet) : m_db(db), current_list_timestamp(0) {
135  testnet ? this->http_client.set_server(this->testnet_endpoint_addr, this->testnet_endpoint_port, boost::none) :
136  this->http_client.set_server(this->endpoint_addr, this->endpoint_port, boost::none);
137  this->testnet = testnet;
138  this->m_p2p = pprotocol;
139  };
140 
141  inline vector<string> getApplicablePublicKeys(uint64_t height, bool convert_to_byte = false) {
142  vector<string> keys;
143  all_of(this->list.begin(), this->list.end(), [&height, &keys, &convert_to_byte](std::unique_ptr<Validator> &v) {
144  if (v->isWithinRange(height)) {
145  const string k = convert_to_byte ? unhex(v->getPublicKey()) : v->getPublicKey();
146  keys.push_back(k);
147  }
148  return true;
149  });
150  return keys;
151  }
152 
153  inline bool loadValidatorsList() {
154 
155  v_list_struct_request req = AUTO_VAL_INIT(req);
156  v_list_struct res = AUTO_VAL_INIT(res);
157 
158  // Try fetching list of validators from JSON endpoint
159  if(this->status == ValidatorsState::Invalid || this->status == ValidatorsState::Expired || this->status == ValidatorsState::NeedsUpdate) {
160  if (!get_http_json("/", res, this->http_client)) {
161  LOG_PRINT_L1("Unable to get validator_list json from " << this->endpoint_addr << ":" << this->endpoint_port);
162  }
163 
164  this->timeout = 60*60*24;
165  list_update_outcome isJsonValid = validate_and_update(res, true);
166 
167  if(isJsonValid == list_update_outcome::Success || isJsonValid == list_update_outcome::Same_List) {
168  MGINFO_MAGENTA("Validators list successfully refreshed from JSON endpoint! Timeout = 12 hours");
169  return true;
170  }
171 
172  //If the list was old, invalid, or had an invalid public key, try getting list of validators from peers
173  if(m_p2p->request_validators_list_to_all() && this->status == ValidatorsState::Valid) {
174  this->timeout = 60*60*1;
175  MGINFO_MAGENTA("Validators list successfully refreshed from peers! Timeout = 1 hour");
176  return true;
177  }
178 
179  //Keep returning true during the grace period
180  if(this->status == ValidatorsState::NeedsUpdate) {
181  LOG_PRINT_L1("Validator List Grace Period");
182  return true;
183  }
184 
185  // If we there was an issue with getting the list from peers, try getting list of validators from db.
186  // This code will only be reached at the daemon start if both endpoint & p2p list are unavailable.
187  string v = m_db.get_validator_list();
188  if(!v.empty()) {
189  this->timeout = 60*60*1;
190  list_update_outcome isDBListValid = setValidatorsList(v, true);
192  MGINFO_MAGENTA("Validators list successfully refreshed from database! Timeout = 1 hour");
193  return true;
194  }
195  }
196 
197 
198  return false;
199  }
200 
201  return true;
202  }
203 
204  inline string getSerializedValidatorList() {
205 
206  if(this->status == ValidatorsState::NeedsUpdate || this->status == ValidatorsState::Expired) {
207  return string("");
208  }
209 
210  return this->serialized_v_list;
211  }
212 
213  inline list_update_outcome setValidatorsList(const string &v_list, bool saveToDB, bool isEmergencyUpdate = false) {
214  v_list_struct res = AUTO_VAL_INIT(res);
215  load_t_from_json(res, v_list);
216 
217  return validate_and_update(res, saveToDB, isEmergencyUpdate);
218  }
219 
220  inline bool isValid() {
221  return this->status == ValidatorsState::Valid || this->status == ValidatorsState::NeedsUpdate;
222  }
223 
224  inline bool isEnabled() {
225  return this->status != ValidatorsState::Disabled;
226  }
227 
228  inline void enable() {
229  this->status = ValidatorsState::Expired;
230  }
231 
232  inline void on_idle() {
233  if(this->status != ValidatorsState::Disabled) {
234  if(validate_expiration() != ValidatorsState::Valid) {
235  m_load_validators_interval.do_call(boost::bind(&Validators::loadValidatorsList, this));
236  }
237  }
238  }
239  };
240  }
241 }
242 
243 #endif //ELECTRONEUM_VALIDATORS_H
virtual bool request_validators_list_to_all()=0
vector< string > getApplicablePublicKeys(uint64_t height, bool convert_to_byte=false)
Definition: validators.h:141
virtual std::string get_validator_list() const =0
Validators(cryptonote::BlockchainDB &db, cryptonote::i_cryptonote_protocol *pprotocol, bool testnet)
Definition: validators.h:134
bool isValid()
Definition: validators.h:220
uint64_t height
Definition: blockchain.cpp:87
string getSerializedValidatorList()
Definition: validators.h:204
void on_idle()
Definition: validators.h:232
Definition: block_queue.cpp:41
bool isWithinRange(uint64_t height)
Definition: validators.h:98
Definition: validators_commands_defs.h:61
void enable()
Definition: validators.h:228
void setEndHeight(uint64_t end_height)
Definition: validators.h:94
time_t last_updated
Definition: validators.h:115
uint64_t startHeight
Definition: validators.h:75
const uint64_t getStartHeight()
Definition: validators.h:86
const string getPublicKey()
Definition: validators.h:82
Definition: validators.h:103
cryptonote::i_cryptonote_protocol * m_p2p
Definition: validators.h:123
Definition: validators.cpp:35
bool loadValidatorsList()
Definition: validators.h:153
const uint64_t getEndHeight()
Definition: validators.h:90
string serialized_v_list
Definition: validators.h:113
string publicKey
Definition: validators.h:74
Definition: validators.h:72
ValidatorsState
Definition: validators.h:53
uint64_t current_list_timestamp
Definition: validators.h:106
vector< std::unique_ptr< Validator > > list
Definition: validators.h:105
uint64_t endHeight
Definition: validators.h:76
Definition: validators_commands_defs.h:66
bool isEnabled()
Definition: validators.h:224
list_update_outcome
Definition: validators.h:61
The BlockchainDB backing store interface declaration/contract.
Definition: blockchain_db.h:342
once_a_time_seconds< 60, true > m_load_validators_interval
Definition: validators.h:119
cryptonote::BlockchainDB & m_db
Definition: validators.h:120
list_update_outcome setValidatorsList(const string &v_list, bool saveToDB, bool isEmergencyUpdate=false)
Definition: validators.h:213
epee::net_utils::http::http_simple_client http_client
Definition: validators.h:107
Definition: cryptonote_protocol_handler_common.h:42