Electroneum
checkpoints.cpp
Go to the documentation of this file.
1 // Copyrights(c) 2017-2021, The Electroneum Project
2 // Copyrights(c) 2014-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 // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31 
32 #include "checkpoints.h"
33 
34 #include "common/dns_utils.h"
35 #include "string_tools.h"
36 #include "storages/portable_storage_template_helper.h" // epee json include
38 #include <functional>
39 #include <vector>
40 
41 using namespace epee;
42 
43 #undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
44 #define ELECTRONEUM_DEFAULT_LOG_CATEGORY "checkpoints"
45 
46 namespace cryptonote
47 {
51  struct t_hashline
52  {
59  };
60 
64  struct t_hash_json {
65  std::vector<t_hashline> hashlines;
67  KV_SERIALIZE(hashlines)
69  };
70 
71  //---------------------------------------------------------------------------
73  {
74  }
75  //---------------------------------------------------------------------------
76  bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
77  {
78  crypto::hash h = crypto::null_hash;
79  bool r = epee::string_tools::hex_to_pod(hash_str, h);
80  CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!");
81 
82  // return false if adding at a height we already have AND the hash is different
83  if (m_points.count(height))
84  {
85  CHECK_AND_ASSERT_MES(h == m_points[height], false, "Checkpoint at given height already exists, and hash for new checkpoint was different!");
86  }
87  m_points[height] = h;
88  return true;
89  }
90  //---------------------------------------------------------------------------
91  bool checkpoints::is_in_checkpoint_zone(uint64_t height) const
92  {
93  return !m_points.empty() && (height <= (--m_points.end())->first);
94  }
95  //---------------------------------------------------------------------------
96  bool checkpoints::check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const
97  {
98  auto it = m_points.find(height);
99  is_a_checkpoint = it != m_points.end();
100  if(!is_a_checkpoint)
101  return true;
102 
103  if(it->second == h)
104  {
105  MINFO("CHECKPOINT PASSED FOR HEIGHT " << height << " " << h);
106  return true;
107  }else
108  {
109  MWARNING("CHECKPOINT FAILED FOR HEIGHT " << height << ". EXPECTED HASH: " << it->second << ", FETCHED HASH: " << h);
110  return false;
111  }
112  }
113  //---------------------------------------------------------------------------
114  bool checkpoints::check_block(uint64_t height, const crypto::hash& h) const
115  {
116  bool ignored;
117  return check_block(height, h, ignored);
118  }
119  //---------------------------------------------------------------------------
120  //FIXME: is this the desired behavior?
121  bool checkpoints::is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const
122  {
123  if (0 == block_height)
124  return false;
125 
126  auto it = m_points.upper_bound(blockchain_height);
127  // Is blockchain_height before the first checkpoint?
128  if (it == m_points.begin())
129  return true;
130 
131  --it;
132  uint64_t checkpoint_height = it->first;
133  return checkpoint_height < block_height;
134  }
135  //---------------------------------------------------------------------------
136  uint64_t checkpoints::get_max_height() const
137  {
138  if (m_points.empty())
139  return 0;
140  return m_points.rbegin()->first;
141  }
142  //---------------------------------------------------------------------------
143  const std::map<uint64_t, crypto::hash>& checkpoints::get_points() const
144  {
145  return m_points;
146  }
147 
148  bool checkpoints::check_for_conflicts(const checkpoints& other) const
149  {
150  for (auto& pt : other.get_points())
151  {
152  if (m_points.count(pt.first))
153  {
154  CHECK_AND_ASSERT_MES(pt.second == m_points.at(pt.first), false, "Checkpoint at given height already exists, and hash for new checkpoint was different!");
155  }
156  }
157  return true;
158  }
159 
160  bool checkpoints::init_default_checkpoints(network_type nettype)
161  {
162  if (nettype == MAINNET)
163  {
164  ADD_CHECKPOINT(1, "4536e1e23ff7179a126a7e61cd9e89ded0e258176f2bc879c999caa155f68cc3");
165  ADD_CHECKPOINT(10, "e5aefcb1d575a788ecfb65bb7be3bdd135eb76ccefb38a60d7800e86d25d408e");
166  ADD_CHECKPOINT(100, "e3548600cc0e2991af4f36bbf44addd95051748fc09e8cac5f8237fd841132c0");
167  ADD_CHECKPOINT(1000, "d7ec8a6329948fee02cdc95b13f286bd69fe9540863a80dfff7fe14940756293");
168  ADD_CHECKPOINT(10000, "95dad4575ba43eb0d4ba9b6081d5d52e6a74fc8fe3391d9628f78ddd3b71c965");
169  ADD_CHECKPOINT(100000, "a7b51ca66b2525903efbd4a32604a7ad5000df4b9da8bdd9cb3062cb014b0cad");
170  ADD_CHECKPOINT(150000, "e9b66d3f12f9cedece7d9925721b15f1ec6cb2f6b438b3ddd288237c27ffe20e");
171  ADD_CHECKPOINT(179839, "f8631f50ef79b840cba9fe3484764d0c7515ff2884e1f5be2f7298a4d08e88ee");
172  ADD_CHECKPOINT(179840, "74958c1b19505ab49babc91dfd14251146256873ae875ac97c26fb2000490e70");
173  ADD_CHECKPOINT(179841, "8a793f1aef368e83fa72ac3a236309c06ae7726958120514e0f6d33ff3b24548");
174  ADD_CHECKPOINT(200000, "9a7853584fbe0d88746d3d7bb6a3efd02ecaa3f0158808fde9f3c8339b3d5d8f");
175  ADD_CHECKPOINT(250000, "0b4d542eeaf6fbd5ceb196ca5ed44edb6ee0c0f1cdf391ba62710b04e1da9f29");
176  ADD_CHECKPOINT(300000, "e3d192196c70c259164fec04868d5cf21a57242cccf54ca0ba9fd8eaeddb8d72");
177  ADD_CHECKPOINT(307499, "c08f9eecdebf4f1f99c4c273368df54422e6861829213ad5d0dbde1cf6f4f08c");
178  ADD_CHECKPOINT(307500, "a65844a64acf5d0aa421892dee64e3552ef390fd29894b7d6c77d08d6609952e");
179  ADD_CHECKPOINT(307501, "4a5a86a4c6ecee29c2d41d8f633e82a5b3340e354c55f2767f722fc03b950fae");
180  ADD_CHECKPOINT(310000, "82dfd6ee74a5ae7526af923f1637b59082ef917d84ad80944edb1debd557bb96");
181  ADD_CHECKPOINT(400000, "251e07872ce8b05dedafbce2dd27f978e71a46aca7fa3b6cdbd94d6b357b5078");
182  ADD_CHECKPOINT(500000, "c2f37b178f4e1cf3460bcefd6eaf14eeaf4258ee67b97e6146b171766bd8101d");
183  ADD_CHECKPOINT(600000, "e8eeceec76ea9718ebf7fac34250403f586d01224b343c6e122baa0799023a4f");
184  ADD_CHECKPOINT(700000, "09af67f7f5b01219dd18c59a424a7570cadfe3c50408180fcaf12cec205155f7");
185  ADD_CHECKPOINT(800000, "748bfc3c736ac106a8c731114648b8c11c0c2bc3d6b9ab074bbbfc8cc1914a3f");
186  ADD_CHECKPOINT(900000, "e0fce3c156932d38d8bde4e21fabbf2a8208e96fb1b0848cc796d7338a70f7de");
187  ADD_CHECKPOINT(1000000, "26da34bde63cfb6447e0dcc190b00e4db04127e2673d48316e63e64c661ab19c");
188  ADD_CHECKPOINT(1100000, "d9d9637c9468c3d8a3a552cef38e52effbe79d0f140b0a0551d5c15f61e07a08");
189  ADD_CHECKPOINT(1811310, "f09bc360b87fd1161e28391528e432e7bde14e5183249c06a9db93a0c624499a");
190  }
191  if (nettype == TESTNET){
192  }
193  return true;
194  }
195 
196  bool checkpoints::load_checkpoints_from_json(const std::string &json_hashfile_fullpath)
197  {
198  boost::system::error_code errcode;
199  if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode)))
200  {
201  LOG_PRINT_L1("Blockchain checkpoints file not found");
202  return true;
203  }
204 
205  LOG_PRINT_L1("Adding checkpoints from blockchain hashfile");
206 
207  uint64_t prev_max_height = get_max_height();
208  LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height);
210  if (!epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath))
211  {
212  MERROR("Error loading checkpoints from " << json_hashfile_fullpath);
213  return false;
214  }
215  for (std::vector<t_hashline>::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); )
216  {
218  height = it->height;
219  if (height <= prev_max_height) {
220  LOG_PRINT_L1("ignoring checkpoint height " << height);
221  } else {
222  std::string blockhash = it->hash;
223  LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash);
224  ADD_CHECKPOINT(height, blockhash);
225  }
226  ++it;
227  }
228 
229  return true;
230  }
231 
232  bool checkpoints::load_checkpoints_from_dns(network_type nettype)
233  {
234  std::vector<std::string> records;
235 
236  // All four ElectroneumPulse domains have DNSSEC on and valid
237  static const std::vector<std::string> dns_urls = {
238  "checkpoints.electroneumpulse.com",
239  "checkpoints.electroneumpulse.info",
240  "checkpoints.electroneumpulse.net",
241  "checkpoints.electroneumpulse.org"
242  };
243 
244  static const std::vector<std::string> testnet_dns_urls = {
245  "testpoints.electroneumpulse.com",
246  "testpoints.electroneumpulse.info",
247  "testpoints.electroneumpulse.net",
248  "testpoints.electroneumpulse.org"
249  };
250 
251  static const std::vector<std::string> stagenet_dns_urls = {
252  "stagenetpoints.electroneumpulse.com",
253  "stagenetpoints.electroneumpulse.info",
254  "stagenetpoints.electroneumpulse.net",
255  "stagenetpoints.electroneumpulse.org"
256  };
257 
258  if (!tools::dns_utils::load_txt_records_from_dns(records, nettype == TESTNET ? testnet_dns_urls : nettype == STAGENET ? stagenet_dns_urls : dns_urls, "checkpoints"))
259  return true; // why true ?
260 
261  for (const auto& record : records)
262  {
263  auto pos = record.find(":");
264  if (pos != std::string::npos)
265  {
268 
269  // parse the first part as uint64_t,
270  // if this fails move on to the next record
271  std::stringstream ss(record.substr(0, pos));
272  if (!(ss >> height))
273  {
274  continue;
275  }
276 
277  // parse the second part as crypto::hash,
278  // if this fails move on to the next record
279  std::string hashStr = record.substr(pos + 1);
280  if (!epee::string_tools::hex_to_pod(hashStr, hash))
281  {
282  continue;
283  }
284 
285  ADD_CHECKPOINT(height, hashStr);
286  }
287  }
288  return true;
289  }
290 
291  bool checkpoints::load_new_checkpoints(const std::string &json_hashfile_fullpath, network_type nettype, bool dns)
292  {
293  bool result;
294 
295  result = load_checkpoints_from_json(json_hashfile_fullpath);
296  if (dns)
297  {
298  result &= load_checkpoints_from_dns(nettype);
299  }
300 
301  return result;
302  }
303 }
#define MERROR(x)
Definition: misc_log_ex.h:73
#define MINFO(x)
Definition: misc_log_ex.h:75
std::vector< t_hashline > hashlines
the checkpoint lines from the file
Definition: checkpoints.cpp:65
#define LOG_PRINT_L1(x)
Definition: misc_log_ex.h:100
::std::string string
Definition: gtest-port.h:1097
#define ADD_CHECKPOINT(h, hash)
Definition: checkpoints.h:38
#define CHECK_AND_ASSERT_MES(expr, fail_ret_val, message)
Definition: misc_log_ex.h:181
uint64_t height
Definition: blockchain.cpp:91
#define KV_SERIALIZE(varialble)
struct hash_func hashes[]
Holds cryptonote related classes and helpers.
Definition: ban.cpp:40
struct for loading many checkpoints from json
Definition: checkpoints.cpp:64
unsigned __int64 uint64_t
Definition: stdint.h:136
bool hex_to_pod(const std::string &hex_str, t_pod_type &s)
Definition: string_tools.h:324
#define MWARNING(x)
Definition: misc_log_ex.h:74
std::string hash
the hash for the checkpoint
Definition: checkpoints.cpp:54
uint64_t height
the height of the checkpoint
Definition: checkpoints.cpp:53
struct for loading a checkpoint from json
Definition: checkpoints.cpp:51
POD_CLASS hash
Definition: hash.h:50
bool load_t_from_json_file(t_struct &out, const std::string &json_file)
A container for blockchain checkpoints.
Definition: checkpoints.h:51
bool load_txt_records_from_dns(std::vector< std::string > &good_records, const std::vector< std::string > &dns_urls, std::string type)
Definition: dns_utils.cpp:515
const std::map< uint64_t, crypto::hash > & get_points() const
gets the checkpoints container
#define END_KV_SERIALIZE_MAP()
#define BEGIN_KV_SERIALIZE_MAP()