Electroneum
cryptonote::HardFork Class Reference

#include <hardfork.h>

Collaboration diagram for cryptonote::HardFork:

Classes

struct  Params
 

Public Types

enum  State { LikelyForked, UpdateNeeded, Ready }
 

Public Member Functions

 HardFork (cryptonote::BlockchainDB &db, uint8_t original_version=1, uint64_t original_version_till_height=DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT, time_t forked_time=DEFAULT_FORKED_TIME, time_t update_time=DEFAULT_UPDATE_TIME, uint64_t window_size=DEFAULT_WINDOW_SIZE, uint8_t default_threshold_percent=DEFAULT_THRESHOLD_PERCENT)
 creates a new HardFork object More...
 
bool add_fork (uint8_t version, uint64_t height, uint8_t threshold, time_t time)
 add a new hardfork height More...
 
bool add_fork (uint8_t version, uint64_t height, time_t time)
 add a new hardfork height More...
 
void init ()
 initialize the object More...
 
bool check (const cryptonote::block &block) const
 check whether a new block would be accepted More...
 
bool check_for_height (const cryptonote::block &block, uint64_t height) const
 same as check, but for a particular height, rather than the top More...
 
bool add (const cryptonote::block &block, uint64_t height)
 add a new block More...
 
bool reorganize_from_block_height (uint64_t height)
 called when the blockchain is reorganized More...
 
bool reorganize_from_chain_height (uint64_t height)
 
void on_block_popped (uint64_t new_chain_height)
 called when one or more blocks are popped from the blockchain More...
 
State get_state (time_t t) const
 returns current state at the given time More...
 
State get_state () const
 
uint8_t get (uint64_t height) const
 returns the hard fork version for the given block height More...
 
uint8_t get_ideal_version () const
 returns the latest "ideal" version More...
 
uint8_t get_ideal_version (uint64_t height) const
 returns the "ideal" version for a given height More...
 
uint8_t get_next_version () const
 returns the next version More...
 
uint8_t get_current_version () const
 returns the current version More...
 
uint64_t get_earliest_ideal_height_for_version (uint8_t version) const
 returns the earliest block a given version may activate More...
 
bool get_voting_info (uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
 returns information about current voting state More...
 
uint64_t get_window_size () const
 returns the size of the voting window in blocks More...
 

Static Public Attributes

static const uint64_t DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT = 0
 
static const time_t DEFAULT_FORKED_TIME = 31557600
 
static const time_t DEFAULT_UPDATE_TIME = 31557600 / 2
 
static const uint64_t DEFAULT_WINDOW_SIZE = 10080
 
static const uint8_t DEFAULT_THRESHOLD_PERCENT = 80
 

Detailed Description

Definition at line 39 of file hardfork.h.

Member Enumeration Documentation

◆ State

Enumerator
LikelyForked 
UpdateNeeded 
Ready 

Definition at line 42 of file hardfork.h.

Constructor & Destructor Documentation

◆ HardFork()

HardFork::HardFork ( cryptonote::BlockchainDB db,
uint8_t  original_version = 1,
uint64_t  original_version_till_height = DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT,
time_t  forked_time = DEFAULT_FORKED_TIME,
time_t  update_time = DEFAULT_UPDATE_TIME,
uint64_t  window_size = DEFAULT_WINDOW_SIZE,
uint8_t  default_threshold_percent = DEFAULT_THRESHOLD_PERCENT 
)

creates a new HardFork object

Parameters
original_versionthe block version for blocks 0 through to the first fork
forked_timethe time in seconds before thinking we're forked
update_timethe time in seconds before thinking we need to update
window_sizethe size of the window in blocks to consider for version voting
default_threshold_percentthe size of the majority in percents

Definition at line 58 of file hardfork.cpp.

58  :
59  db(db),
60  forked_time(forked_time),
61  update_time(update_time),
62  window_size(window_size),
63  default_threshold_percent(default_threshold_percent),
64  original_version(original_version),
65  original_version_till_height(original_version_till_height),
66  current_fork_index(0)
67 {
68  if (window_size == 0)
69  throw "window_size needs to be strictly positive";
70  if (default_threshold_percent > 100)
71  throw "default_threshold_percent needs to be between 0 and 100";
72 }

Member Function Documentation

◆ add()

bool HardFork::add ( const cryptonote::block block,
uint64_t  height 
)

add a new block

returns true if no error, false otherwise

Parameters
blockthe new block

Definition at line 164 of file hardfork.cpp.

165 {
166  return add(::get_block_version(block), ::get_block_vote(block), height);
167 }
uint64_t height
Definition: blockchain.cpp:91
bool add(const cryptonote::block &block, uint64_t height)
add a new block
Definition: hardfork.cpp:164
Here is the caller graph for this function:

◆ add_fork() [1/2]

bool HardFork::add_fork ( uint8_t  version,
uint64_t  height,
uint8_t  threshold,
time_t  time 
)

add a new hardfork height

returns true if no error, false otherwise

Parameters
versionthe major block version for the fork
heightThe height the hardfork takes effect
thresholdThe threshold of votes needed for this fork (0-100)
timeApproximate time of the hardfork (seconds since epoch)

Definition at line 74 of file hardfork.cpp.

75 {
77 
78  // add in order
79  if (version == 0)
80  return false;
81  if (!heights.empty()) {
82  if (version <= heights.back().version)
83  return false;
84  if (height <= heights.back().height)
85  return false;
86  if (time <= heights.back().time)
87  return false;
88  }
89  if (threshold > 100)
90  return false;
91  heights.push_back(Params(version, height, threshold, time));
92  return true;
93 }
uint64_t height
Definition: blockchain.cpp:91
time_t time
Definition: blockchain.cpp:93
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
version
Supported socks variants.
Definition: socks.h:57
uint8_t threshold
Definition: blockchain.cpp:92
Here is the caller graph for this function:

◆ add_fork() [2/2]

bool HardFork::add_fork ( uint8_t  version,
uint64_t  height,
time_t  time 
)

add a new hardfork height

returns true if no error, false otherwise

Parameters
versionthe major block version for the fork
heightThe height the hardfork takes effect
timeApproximate time of the hardfork (seconds since epoch)

Definition at line 95 of file hardfork.cpp.

96 {
97  return add_fork(version, height, default_threshold_percent, time);
98 }
uint64_t height
Definition: blockchain.cpp:91
time_t time
Definition: blockchain.cpp:93
version
Supported socks variants.
Definition: socks.h:57
bool add_fork(uint8_t version, uint64_t height, uint8_t threshold, time_t time)
add a new hardfork height
Definition: hardfork.cpp:74
Here is the call graph for this function:

◆ check()

bool HardFork::check ( const cryptonote::block block) const

check whether a new block would be accepted

returns true if the block is accepted, false otherwise

Parameters
blockthe new block

This check is made by add. It is exposed publicly to allow the caller to inexpensively check whether a block would be accepted or rejected by its version number. Indeed, if this check could only be done as part of add, the caller would either have to add the block to the blockchain first, then call add, then have to pop the block from the blockchain if its version did not satisfy the hard fork requirements, or call add first, then, if the hard fork requirements are met, add the block to the blockchain, upon which a failure (the block being invalid, double spending, etc) would cause the hardfork object to reorganize.

Definition at line 116 of file hardfork.cpp.

117 {
118  CRITICAL_REGION_LOCAL(lock);
119  return do_check(::get_block_version(block), ::get_block_vote(block));
120 }
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228

◆ check_for_height()

bool HardFork::check_for_height ( const cryptonote::block block,
uint64_t  height 
) const

same as check, but for a particular height, rather than the top

NOTE: this does not play well with voting, and relies on voting to be disabled (that is, forks happen on the scheduled date, whether or not enough blocks have voted for the fork).

returns true if no error, false otherwise

Parameters
blockthe new block
heightwhich height to check for

Definition at line 129 of file hardfork.cpp.

130 {
131  CRITICAL_REGION_LOCAL(lock);
132  return do_check_for_height(::get_block_version(block), ::get_block_vote(block), height);
133 }
uint64_t height
Definition: blockchain.cpp:91
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
Here is the caller graph for this function:

◆ get()

uint8_t HardFork::get ( uint64_t  height) const

returns the hard fork version for the given block height

Parameters
heightheight of the block to check

Definition at line 348 of file hardfork.cpp.

349 {
350  CRITICAL_REGION_LOCAL(lock);
351  if (height > db.height()) {
352  assert(false);
353  return 255;
354  }
355  if (height == db.height()) {
356  return get_current_version();
357  }
358  return db.get_hard_fork_version(height);
359 }
uint8_t get_current_version() const
returns the current version
Definition: hardfork.cpp:361
uint64_t height
Definition: blockchain.cpp:91
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
virtual uint64_t height() const =0
fetch the current blockchain height
virtual uint8_t get_hard_fork_version(uint64_t height) const =0
checks which hardfork version a height is on
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_current_version()

uint8_t HardFork::get_current_version ( ) const

returns the current version

This is the latest version that's past its trigger date and had enough votes at one point in the past.

Definition at line 361 of file hardfork.cpp.

362 {
363  CRITICAL_REGION_LOCAL(lock);
364  return heights[current_fork_index].version;
365 }
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
Here is the caller graph for this function:

◆ get_earliest_ideal_height_for_version()

uint64_t HardFork::get_earliest_ideal_height_for_version ( uint8_t  version) const

returns the earliest block a given version may activate

Definition at line 384 of file hardfork.cpp.

385 {
386  uint64_t height = std::numeric_limits<uint64_t>::max();
387  for (auto i = heights.rbegin(); i != heights.rend(); ++i) {
388  if (i->version >= version) {
389  height = i->height;
390  } else {
391  break;
392  }
393  }
394  return height;
395 }
uint64_t height
Definition: blockchain.cpp:91
unsigned __int64 uint64_t
Definition: stdint.h:136
version
Supported socks variants.
Definition: socks.h:57
Here is the caller graph for this function:

◆ get_ideal_version() [1/2]

uint8_t HardFork::get_ideal_version ( ) const

returns the latest "ideal" version

This is the latest version that's been scheduled

Definition at line 367 of file hardfork.cpp.

368 {
369  CRITICAL_REGION_LOCAL(lock);
370  return heights.back().version;
371 }
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
Here is the caller graph for this function:

◆ get_ideal_version() [2/2]

uint8_t HardFork::get_ideal_version ( uint64_t  height) const

returns the "ideal" version for a given height

Parameters
heightheight of the block to check

Definition at line 373 of file hardfork.cpp.

374 {
375  CRITICAL_REGION_LOCAL(lock);
376  for (unsigned int n = heights.size() - 1; n > 0; --n) {
377  if (height >= heights[n].height) {
378  return heights[n].version;
379  }
380  }
381  return original_version;
382 }
uint64_t height
Definition: blockchain.cpp:91
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228

◆ get_next_version()

uint8_t HardFork::get_next_version ( ) const

returns the next version

This is the version which will we fork to next

Definition at line 397 of file hardfork.cpp.

398 {
399  CRITICAL_REGION_LOCAL(lock);
400  uint64_t height = db.height();
401  for (auto i = heights.rbegin(); i != heights.rend(); ++i) {
402  if (height >= i->height) {
403  return (i == heights.rbegin() ? i : (i - 1))->version;
404  }
405  }
406  return original_version;
407 }
uint64_t height
Definition: blockchain.cpp:91
unsigned __int64 uint64_t
Definition: stdint.h:136
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
virtual uint64_t height() const =0
fetch the current blockchain height
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_state() [1/2]

HardFork::State HardFork::get_state ( time_t  t) const

returns current state at the given time

Based on the approximate time of the last known hard fork, estimate whether we need to update, or if we're way behind

Parameters
tthe time to consider

Definition at line 327 of file hardfork.cpp.

328 {
329  CRITICAL_REGION_LOCAL(lock);
330 
331  // no hard forks setup yet
332  if (heights.size() <= 1)
333  return Ready;
334 
335  time_t t_last_fork = heights.back().time;
336  if (t >= t_last_fork + forked_time)
337  return LikelyForked;
338  if (t >= t_last_fork + update_time)
339  return UpdateNeeded;
340  return Ready;
341 }
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
Here is the caller graph for this function:

◆ get_state() [2/2]

HardFork::State HardFork::get_state ( ) const

Definition at line 343 of file hardfork.cpp.

344 {
345  return get_state(time(NULL));
346 }
time_t time
Definition: blockchain.cpp:93
State get_state() const
Definition: hardfork.cpp:343

◆ get_voting_info()

bool HardFork::get_voting_info ( uint8_t  version,
uint32_t window,
uint32_t votes,
uint32_t threshold,
uint64_t earliest_height,
uint8_t voting 
) const

returns information about current voting state

returns true if the given version is enabled (ie, the current version is at least the passed version), false otherwise

Parameters
versionthe version to check voting for
windowthe number of blocks considered in voting
votesnumber of votes for next version
thresholdnumber of votes needed to switch to next version
earliest_heightearliest height at which the version can take effect

Definition at line 409 of file hardfork.cpp.

410 {
411  CRITICAL_REGION_LOCAL(lock);
412 
413  const uint8_t current_version = heights[current_fork_index].version;
414  const bool enabled = current_version >= version;
415  window = versions.size();
416  votes = 0;
417  for (size_t n = version; n < 256; ++n)
418  votes += last_versions[n];
419  threshold = (window * heights[current_fork_index].threshold + 99) / 100;
420  //assert((votes >= threshold) == enabled);
422  voting = heights.back().version;
423  return enabled;
424 }
unsigned char uint8_t
Definition: stdint.h:124
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
version
Supported socks variants.
Definition: socks.h:57
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const
returns the earliest block a given version may activate
Definition: hardfork.cpp:384
uint8_t threshold
Definition: blockchain.cpp:92
Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_window_size()

uint64_t cryptonote::HardFork::get_window_size ( ) const
inline

returns the size of the voting window in blocks

Definition at line 232 of file hardfork.h.

232 { return window_size; }

◆ init()

void HardFork::init ( )

initialize the object

Must be done after adding all the required hardforks via add above

Definition at line 169 of file hardfork.cpp.

170 {
171  CRITICAL_REGION_LOCAL(lock);
172 
173  // add a placeholder for the default version, to avoid special cases
174  if (heights.empty())
175  heights.push_back(Params(original_version, 0, 0, 0));
176 
177  versions.clear();
178  for (size_t n = 0; n < 256; ++n)
179  last_versions[n] = 0;
180  current_fork_index = 0;
181 
182  // restore state from DB
183  uint64_t height = db.height();
184  if (height > window_size)
185  height -= window_size - 1;
186  else
187  height = 1;
188 
189  rescan_from_chain_height(height);
190  MDEBUG("init done");
191 }
uint64_t height
Definition: blockchain.cpp:91
#define MDEBUG(x)
Definition: misc_log_ex.h:76
unsigned __int64 uint64_t
Definition: stdint.h:136
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
virtual uint64_t height() const =0
fetch the current blockchain height
Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_block_popped()

void HardFork::on_block_popped ( uint64_t  new_chain_height)

called when one or more blocks are popped from the blockchain

The current fork will be updated by looking up the db, which is much cheaper than recomputing everything

Parameters
new_chain_heightthe height of the chain after popping

Definition at line 287 of file hardfork.cpp.

288 {
289  CHECK_AND_ASSERT_THROW_MES(nblocks > 0, "nblocks must be greater than 0");
290 
291  CRITICAL_REGION_LOCAL(lock);
292 
293  const uint64_t new_chain_height = db.height();
294  const uint64_t old_chain_height = new_chain_height + nblocks;
296  for (uint64_t height = old_chain_height - 1; height >= new_chain_height; --height)
297  {
298  version = versions.back();
299  last_versions[version]--;
300  versions.pop_back();
302  versions.push_front(version);
303  last_versions[version]++;
304  }
305 
306  // does not take voting into account
307  for (current_fork_index = heights.size() - 1; current_fork_index > 0; --current_fork_index)
308  if (new_chain_height >= heights[current_fork_index].height)
309  break;
310 }
#define CHECK_AND_ASSERT_THROW_MES(expr, message)
Definition: misc_log_ex.h:173
uint64_t height
Definition: blockchain.cpp:91
unsigned char uint8_t
Definition: stdint.h:124
unsigned __int64 uint64_t
Definition: stdint.h:136
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
virtual uint64_t height() const =0
fetch the current blockchain height
version
Supported socks variants.
Definition: socks.h:57
virtual uint8_t get_hard_fork_version(uint64_t height) const =0
checks which hardfork version a height is on
Here is the call graph for this function:

◆ reorganize_from_block_height()

bool HardFork::reorganize_from_block_height ( uint64_t  height)

called when the blockchain is reorganized

This will rescan the blockchain to determine which hard forks have been triggered

returns true if no error, false otherwise

Parameters
blockchainthe blockchain
heightof the last block kept from the previous blockchain

Definition at line 202 of file hardfork.cpp.

203 {
204  CRITICAL_REGION_LOCAL(lock);
205  if (height >= db.height())
206  return false;
207 
208  bool stop_batch = db.batch_start();
209 
210  versions.clear();
211 
212  for (size_t n = 0; n < 256; ++n)
213  last_versions[n] = 0;
214  const uint64_t rescan_height = height >= (window_size - 1) ? height - (window_size -1) : 0;
215  const uint8_t start_version = height == 0 ? original_version : db.get_hard_fork_version(height);
216  while (current_fork_index > 0 && heights[current_fork_index].version > start_version) {
217  --current_fork_index;
218  }
219  for (uint64_t h = rescan_height; h <= height; ++h) {
221  const uint8_t v = get_effective_version(get_block_vote(b));
222  last_versions[v]++;
223  versions.push_back(v);
224  }
225 
226  uint8_t voted = get_voted_fork_index(height + 1);
227  if (voted > current_fork_index) {
228  current_fork_index = voted;
229  }
230 
231  const uint64_t bc_height = db.height();
232  for (uint64_t h = height + 1; h < bc_height; ++h) {
233  add(db.get_block_from_height(h), h);
234  }
235 
236  if (stop_batch)
237  db.batch_stop();
238 
239  return true;
240 }
uint64_t height
Definition: blockchain.cpp:91
unsigned char uint8_t
Definition: stdint.h:124
virtual block get_block_from_height(const uint64_t &height) const
fetch a block by height
bool add(const cryptonote::block &block, uint64_t height)
add a new block
Definition: hardfork.cpp:164
unsigned __int64 uint64_t
Definition: stdint.h:136
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
virtual uint64_t height() const =0
fetch the current blockchain height
virtual void batch_stop()=0
ends a batch transaction
version
Supported socks variants.
Definition: socks.h:57
virtual uint8_t get_hard_fork_version(uint64_t height) const =0
checks which hardfork version a height is on
virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0)=0
tells the BlockchainDB to start a new "batch" of blocks
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reorganize_from_chain_height()

bool HardFork::reorganize_from_chain_height ( uint64_t  height)

Definition at line 242 of file hardfork.cpp.

243 {
244  if (height == 0)
245  return false;
247 }
uint64_t height
Definition: blockchain.cpp:91
bool reorganize_from_block_height(uint64_t height)
called when the blockchain is reorganized
Definition: hardfork.cpp:202
Here is the call graph for this function:

Member Data Documentation

◆ DEFAULT_FORKED_TIME

const time_t cryptonote::HardFork::DEFAULT_FORKED_TIME = 31557600
static

Definition at line 49 of file hardfork.h.

◆ DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT

const uint64_t cryptonote::HardFork::DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT = 0
static

Definition at line 48 of file hardfork.h.

◆ DEFAULT_THRESHOLD_PERCENT

const uint8_t cryptonote::HardFork::DEFAULT_THRESHOLD_PERCENT = 80
static

Definition at line 52 of file hardfork.h.

◆ DEFAULT_UPDATE_TIME

const time_t cryptonote::HardFork::DEFAULT_UPDATE_TIME = 31557600 / 2
static

Definition at line 50 of file hardfork.h.

◆ DEFAULT_WINDOW_SIZE

const uint64_t cryptonote::HardFork::DEFAULT_WINDOW_SIZE = 10080
static

Definition at line 51 of file hardfork.h.


The documentation for this class was generated from the following files: