Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::chain::fork_database_impl Struct Reference
Collaboration diagram for sysio::chain::fork_database_impl:

Public Member Functions

 fork_database_impl (const fc::path &data_dir)
 
void open_impl (const std::function< void(block_timestamp_type, const flat_set< digest_type > &, const vector< digest_type > &)> &validator)
 
void close_impl ()
 
block_header_state_ptr get_block_header_impl (const block_id_type &id) const
 
block_state_ptr get_block_impl (const block_id_type &id) const
 
void reset_impl (const block_header_state &root_bhs)
 
void rollback_head_to_root_impl ()
 
void advance_root_impl (const block_id_type &id)
 
void remove_impl (const block_id_type &id)
 
branch_type fetch_branch_impl (const block_id_type &h, uint32_t trim_after_block_num) const
 
block_state_ptr search_on_branch_impl (const block_id_type &h, uint32_t block_num) const
 
pair< branch_type, branch_typefetch_branch_from_impl (const block_id_type &first, const block_id_type &second) const
 
void mark_valid_impl (const block_state_ptr &h)
 
void add_impl (const block_state_ptr &n, bool ignore_duplicate, bool validate, const std::function< void(block_timestamp_type, const flat_set< digest_type > &, const vector< digest_type > &)> &validator)
 

Public Attributes

std::shared_mutex mtx
 
fork_multi_index_type index
 
block_state_ptr root
 
block_state_ptr head
 
fc::path datadir
 

Detailed Description

Definition at line 63 of file fork_database.cpp.

Constructor & Destructor Documentation

◆ fork_database_impl()

sysio::chain::fork_database_impl::fork_database_impl ( const fc::path & data_dir)
inlineexplicit

Definition at line 64 of file fork_database.cpp.

65 :datadir(data_dir)
66 {}

Member Function Documentation

◆ add_impl()

void sysio::chain::fork_database_impl::add_impl ( const block_state_ptr & n,
bool ignore_duplicate,
bool validate,
const std::function< void(block_timestamp_type, const flat_set< digest_type > &, const vector< digest_type > &)> & validator )

Definition at line 348 of file fork_database.cpp.

353 {
354 SYS_ASSERT( root, fork_database_exception, "root not yet set" );
355 SYS_ASSERT( n, fork_database_exception, "attempt to add null block state" );
356
357 auto prev_bh = get_block_header_impl( n->header.previous );
358
359 SYS_ASSERT( prev_bh, unlinkable_block_exception,
360 "unlinkable block", ("id", n->id)("previous", n->header.previous) );
361
362 if( validate ) {
363 try {
364 const auto& exts = n->header_exts;
365
366 if( exts.count(protocol_feature_activation::extension_id()) > 0 ) {
367 const auto& new_protocol_features = std::get<protocol_feature_activation>(exts.lower_bound(protocol_feature_activation::extension_id())->second).protocol_features;
368 validator( n->header.timestamp, prev_bh->activated_protocol_features->protocol_features, new_protocol_features );
369 }
370 } SYS_RETHROW_EXCEPTIONS( fork_database_exception, "serialized fork database is incompatible with configured protocol features" )
371 }
372
373 auto inserted = index.insert(n);
374 if( !inserted.second ) {
375 if( ignore_duplicate ) return;
376 SYS_THROW( fork_database_exception, "duplicate block added", ("id", n->id) );
377 }
378
379 auto candidate = index.get<by_lib_block_num>().begin();
380 if( (*candidate)->is_valid() ) {
381 head = *candidate;
382 }
383 }
#define SYS_THROW(exc_type, FORMAT,...)
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
#define SYS_RETHROW_EXCEPTIONS(exception_type, FORMAT,...)
bool validate(const Authority &auth)
key Invalid authority Invalid transaction Invalid block ID Invalid packed transaction Invalid chain ID Invalid symbol Signature type is not a currently activated type fork_database_exception
block_header_state_ptr get_block_header_impl(const block_id_type &id) const
Here is the call graph for this function:
Here is the caller graph for this function:

◆ advance_root_impl()

void sysio::chain::fork_database_impl::advance_root_impl ( const block_id_type & id)

Definition at line 298 of file fork_database.cpp.

298 {
299 SYS_ASSERT( root, fork_database_exception, "root not yet set" );
300
301 auto new_root = get_block_impl( id );
303 "cannot advance root to a block that does not exist in the fork database" );
304 SYS_ASSERT( new_root->is_valid(), fork_database_exception,
305 "cannot advance root to a block that has not yet been validated" );
306
307
308 deque<block_id_type> blocks_to_remove;
309 for( auto b = new_root; b; ) {
310 blocks_to_remove.emplace_back( b->header.previous );
311 b = get_block_impl( blocks_to_remove.back() );
312 SYS_ASSERT( b || blocks_to_remove.back() == root->id, fork_database_exception, "invariant violation: orphaned branch was present in forked database" );
313 }
314
315 // The new root block should be erased from the fork database index individually rather than with the remove method,
316 // because we do not want the blocks branching off of it to be removed from the fork database.
317 index.erase( index.find( id ) );
318
319 // The other blocks to be removed are removed using the remove method so that orphaned branches do not remain in the fork database.
320 for( const auto& block_id : blocks_to_remove ) {
321 remove_impl( block_id );
322 }
323
324 // Even though fork database no longer needs block or trxs when a block state becomes a root of the tree,
325 // avoid mutating the block state at all, for example clearing the block shared pointer, because other
326 // parts of the code which run asynchronously may later expect it remain unmodified.
327
328 root = new_root;
329 }
block_state_ptr get_block_impl(const block_id_type &id) const
void remove_impl(const block_id_type &id)
Here is the call graph for this function:

◆ close_impl()

void sysio::chain::fork_database_impl::close_impl ( )

Definition at line 196 of file fork_database.cpp.

196 {
197 auto fork_db_dat = datadir / config::forkdb_filename;
198
199 if( !root ) {
200 if( index.size() > 0 ) {
201 elog( "fork_database is in a bad state when closing; not writing out '${filename}'",
202 ("filename", fork_db_dat.generic_string()) );
203 }
204 return;
205 }
206
207 std::ofstream out( fork_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc );
209 fc::raw::pack( out, fork_database::max_supported_version ); // write out current version which is always max_supported_version
210 fc::raw::pack( out, *static_cast<block_header_state*>(&*root) );
211 uint32_t num_blocks_in_fork_db = index.size();
212 fc::raw::pack( out, unsigned_int{num_blocks_in_fork_db} );
213
214 const auto& indx = index.get<by_lib_block_num>();
215
216 auto unvalidated_itr = indx.rbegin();
217 auto unvalidated_end = boost::make_reverse_iterator( indx.lower_bound( false ) );
218
219 auto validated_itr = unvalidated_end;
220 auto validated_end = indx.rend();
221
222 for( bool unvalidated_remaining = (unvalidated_itr != unvalidated_end),
223 validated_remaining = (validated_itr != validated_end);
224
225 unvalidated_remaining || validated_remaining;
226
227 unvalidated_remaining = (unvalidated_itr != unvalidated_end),
228 validated_remaining = (validated_itr != validated_end)
229 )
230 {
231 auto itr = (validated_remaining ? validated_itr : unvalidated_itr);
232
233 if( unvalidated_remaining && validated_remaining ) {
234 if( first_preferred( **validated_itr, **unvalidated_itr ) ) {
235 itr = unvalidated_itr;
236 ++unvalidated_itr;
237 } else {
238 ++validated_itr;
239 }
240 } else if( unvalidated_remaining ) {
241 ++unvalidated_itr;
242 } else {
243 ++validated_itr;
244 }
245
246 fc::raw::pack( out, *(*itr) );
247 }
248
249 if( head ) {
250 fc::raw::pack( out, head->id );
251 } else {
252 elog( "head not set in fork database; '${filename}' will be corrupted",
253 ("filename", fork_db_dat.generic_string()) );
254 }
255
256 index.clear();
257 }
static const uint32_t max_supported_version
static const uint32_t magic_number
#define elog(FORMAT,...)
Definition logger.hpp:130
void pack(Stream &s, const std::deque< T > &value)
Definition raw.hpp:531
bool first_preferred(const block_header_state &lhs, const block_header_state &rhs)
unsigned int uint32_t
Definition stdint.h:126
Here is the call graph for this function:

◆ fetch_branch_from_impl()

pair< branch_type, branch_type > sysio::chain::fork_database_impl::fetch_branch_from_impl ( const block_id_type & first,
const block_id_type & second ) const

Definition at line 457 of file fork_database.cpp.

458 {
459 pair<branch_type,branch_type> result;
460 auto first_branch = (first == root->id) ? root : get_block_impl(first);
461 auto second_branch = (second == root->id) ? root : get_block_impl(second);
462
463 SYS_ASSERT(first_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", first));
464 SYS_ASSERT(second_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", second));
465
466 while( first_branch->block_num > second_branch->block_num )
467 {
468 result.first.push_back(first_branch);
469 const auto& prev = first_branch->header.previous;
470 first_branch = (prev == root->id) ? root : get_block_impl( prev );
471 SYS_ASSERT( first_branch, fork_db_block_not_found,
472 "block ${id} does not exist",
473 ("id", prev)
474 );
475 }
476
477 while( second_branch->block_num > first_branch->block_num )
478 {
479 result.second.push_back( second_branch );
480 const auto& prev = second_branch->header.previous;
481 second_branch = (prev == root->id) ? root : get_block_impl( prev );
482 SYS_ASSERT( second_branch, fork_db_block_not_found,
483 "block ${id} does not exist",
484 ("id", prev)
485 );
486 }
487
488 if (first_branch->id == second_branch->id) return result;
489
490 while( first_branch->header.previous != second_branch->header.previous )
491 {
492 result.first.push_back(first_branch);
493 result.second.push_back(second_branch);
494 const auto &first_prev = first_branch->header.previous;
495 first_branch = get_block_impl( first_prev );
496 const auto &second_prev = second_branch->header.previous;
497 second_branch = get_block_impl( second_prev );
498 SYS_ASSERT( first_branch, fork_db_block_not_found,
499 "block ${id} does not exist",
500 ("id", first_prev)
501 );
502 SYS_ASSERT( second_branch, fork_db_block_not_found,
503 "block ${id} does not exist",
504 ("id", second_prev)
505 );
506 }
507
508 if( first_branch && second_branch )
509 {
510 result.first.push_back(first_branch);
511 result.second.push_back(second_branch);
512 }
513 return result;
514 }
Here is the call graph for this function:

◆ fetch_branch_impl()

branch_type sysio::chain::fork_database_impl::fetch_branch_impl ( const block_id_type & h,
uint32_t trim_after_block_num ) const

Definition at line 423 of file fork_database.cpp.

423 {
424 branch_type result;
425 for( auto s = get_block_impl(h); s; s = get_block_impl( s->header.previous ) ) {
426 if( s->block_num <= trim_after_block_num )
427 result.push_back( s );
428 }
429
430 return result;
431 }
deque< block_state_ptr > branch_type
char * s
Here is the call graph for this function:

◆ get_block_header_impl()

block_header_state_ptr sysio::chain::fork_database_impl::get_block_header_impl ( const block_id_type & id) const

Definition at line 336 of file fork_database.cpp.

336 {
337 if( root->id == id ) {
338 return root;
339 }
340
341 auto itr = index.find( id );
342 if( itr != index.end() )
343 return *itr;
344
345 return block_header_state_ptr();
346 }
std::shared_ptr< block_header_state > block_header_state_ptr
Here is the caller graph for this function:

◆ get_block_impl()

block_state_ptr sysio::chain::fork_database_impl::get_block_impl ( const block_id_type & id) const

Definition at line 573 of file fork_database.cpp.

573 {
574 auto itr = index.find( id );
575 if( itr != index.end() )
576 return *itr;
577 return block_state_ptr();
578 }
std::shared_ptr< block_state > block_state_ptr
Here is the caller graph for this function:

◆ mark_valid_impl()

void sysio::chain::fork_database_impl::mark_valid_impl ( const block_state_ptr & h)

Definition at line 548 of file fork_database.cpp.

548 {
549 if( h->validated ) return;
550
551 auto& by_id_idx = index.get<by_block_id>();
552
553 auto itr = by_id_idx.find( h->id );
554 SYS_ASSERT( itr != by_id_idx.end(), fork_database_exception,
555 "block state not in fork database; cannot mark as valid",
556 ("id", h->id) );
557
558 by_id_idx.modify( itr, []( block_state_ptr& bsp ) {
559 bsp->validated = true;
560 } );
561
562 auto candidate = index.get<by_lib_block_num>().begin();
563 if( first_preferred( **candidate, *head ) ) {
564 head = *candidate;
565 }
566 }
Here is the call graph for this function:

◆ open_impl()

void sysio::chain::fork_database_impl::open_impl ( const std::function< void(block_timestamp_type, const flat_set< digest_type > &, const vector< digest_type > &)> & validator)

Definition at line 113 of file fork_database.cpp.

116 {
119
120 auto fork_db_dat = datadir / config::forkdb_filename;
121 if( fc::exists( fork_db_dat ) ) {
122 try {
123 string content;
124 fc::read_file_contents( fork_db_dat, content );
125
126 fc::datastream<const char*> ds( content.data(), content.size() );
127
128 // validate totem
129 uint32_t totem = 0;
130 fc::raw::unpack( ds, totem );
132 "Fork database file '${filename}' has unexpected magic number: ${actual_totem}. Expected ${expected_totem}",
133 ("filename", fork_db_dat.generic_string())
134 ("actual_totem", totem)
135 ("expected_totem", fork_database::magic_number)
136 );
137
138 // validate version
139 uint32_t version = 0;
140 fc::raw::unpack( ds, version );
143 "Unsupported version of fork database file '${filename}'. "
144 "Fork database version is ${version} while code supports version(s) [${min},${max}]",
145 ("filename", fork_db_dat.generic_string())
146 ("version", version)
149 );
150
151 block_header_state bhs;
152 fc::raw::unpack( ds, bhs );
153 reset_impl( bhs );
154
155 unsigned_int size; fc::raw::unpack( ds, size );
156 for( uint32_t i = 0, n = size.value; i < n; ++i ) {
157 block_state s;
158 fc::raw::unpack( ds, s );
159 // do not populate transaction_metadatas, they will be created as needed in apply_block with appropriate key recovery
160 s.header_exts = s.block->validate_and_extract_header_extensions();
161 add_impl( std::make_shared<block_state>( std::move( s ) ), false, true, validator );
162 }
163 block_id_type head_id;
164 fc::raw::unpack( ds, head_id );
165
166 if( root->id == head_id ) {
167 head = root;
168 } else {
169 head = get_block_impl( head_id );
171 "could not find head while reconstructing fork database from file; '${filename}' is likely corrupted",
172 ("filename", fork_db_dat.generic_string()) );
173 }
174
175 auto candidate = index.get<by_lib_block_num>().begin();
176 if( candidate == index.get<by_lib_block_num>().end() || !(*candidate)->is_valid() ) {
177 SYS_ASSERT( head->id == root->id, fork_database_exception,
178 "head not set to root despite no better option available; '${filename}' is likely corrupted",
179 ("filename", fork_db_dat.generic_string()) );
180 } else {
182 "head not set to best available option available; '${filename}' is likely corrupted",
183 ("filename", fork_db_dat.generic_string()) );
184 }
185 } FC_CAPTURE_AND_RETHROW( (fork_db_dat) )
186
187 fc::remove( fork_db_dat );
188 }
189 }
static const uint32_t min_supported_version
#define FC_CAPTURE_AND_RETHROW(...)
static const Segment ds(Segment::ds)
void unpack(Stream &s, std::deque< T > &value)
Definition raw.hpp:540
bool remove(const path &p)
void read_file_contents(const fc::path &filename, std::string &result)
Definition fstream.cpp:14
bool exists(const path &p)
void create_directories(const path &p)
bool is_directory(const path &p)
fc::sha256 block_id_type
Definition types.hpp:231
void add_impl(const block_state_ptr &n, bool ignore_duplicate, bool validate, const std::function< void(block_timestamp_type, const flat_set< digest_type > &, const vector< digest_type > &)> &validator)
void reset_impl(const block_header_state &root_bhs)
Here is the call graph for this function:

◆ remove_impl()

void sysio::chain::fork_database_impl::remove_impl ( const block_id_type & id)

Definition at line 522 of file fork_database.cpp.

522 {
523 deque<block_id_type> remove_queue{id};
524 const auto& previdx = index.get<by_prev>();
525 const auto& head_id = head->id;
526
527 for( uint32_t i = 0; i < remove_queue.size(); ++i ) {
528 SYS_ASSERT( remove_queue[i] != head_id, fork_database_exception,
529 "removing the block and its descendants would remove the current head block" );
530
531 auto previtr = previdx.lower_bound( remove_queue[i] );
532 while( previtr != previdx.end() && (*previtr)->header.previous == remove_queue[i] ) {
533 remove_queue.emplace_back( (*previtr)->id );
534 ++previtr;
535 }
536 }
537
538 for( const auto& block_id : remove_queue ) {
539 index.erase( block_id );
540 }
541 }
Here is the caller graph for this function:

◆ reset_impl()

void sysio::chain::fork_database_impl::reset_impl ( const block_header_state & root_bhs)

Definition at line 268 of file fork_database.cpp.

268 {
269 index.clear();
270 root = std::make_shared<block_state>();
271 static_cast<block_header_state&>(*root) = root_bhs;
272 root->validated = true;
273 head = root;
274 }
Here is the caller graph for this function:

◆ rollback_head_to_root_impl()

void sysio::chain::fork_database_impl::rollback_head_to_root_impl ( )

Definition at line 281 of file fork_database.cpp.

281 {
282 auto& by_id_idx = index.get<by_block_id>();
283 auto itr = by_id_idx.begin();
284 while (itr != by_id_idx.end()) {
285 by_id_idx.modify( itr, [&]( block_state_ptr& bsp ) {
286 bsp->validated = false;
287 } );
288 ++itr;
289 }
290 head = root;
291 }

◆ search_on_branch_impl()

block_state_ptr sysio::chain::fork_database_impl::search_on_branch_impl ( const block_id_type & h,
uint32_t block_num ) const

Definition at line 438 of file fork_database.cpp.

438 {
439 for( auto s = get_block_impl(h); s; s = get_block_impl( s->header.previous ) ) {
440 if( s->block_num == block_num )
441 return s;
442 }
443
444 return {};
445 }
Here is the call graph for this function:

Member Data Documentation

◆ datadir

fc::path sysio::chain::fork_database_impl::datadir

Definition at line 72 of file fork_database.cpp.

◆ head

block_state_ptr sysio::chain::fork_database_impl::head

Definition at line 71 of file fork_database.cpp.

◆ index

fork_multi_index_type sysio::chain::fork_database_impl::index

Definition at line 69 of file fork_database.cpp.

◆ mtx

std::shared_mutex sysio::chain::fork_database_impl::mtx

Definition at line 68 of file fork_database.cpp.

◆ root

block_state_ptr sysio::chain::fork_database_impl::root

Definition at line 70 of file fork_database.cpp.


The documentation for this struct was generated from the following file: