1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15- import datetime
1615import sys
1716import time
1817from cProfile import Profile
5352from hathor .reward_lock import is_spent_reward_locked
5453from hathor .stratum import StratumFactory
5554from hathor .transaction import BaseTransaction , Block , MergeMinedBlock , Transaction , TxVersion
56- from hathor .transaction .exceptions import TxValidationError
5755from hathor .transaction .storage .exceptions import TransactionDoesNotExist
5856from hathor .transaction .storage .transaction_storage import TransactionStorage
5957from hathor .transaction .storage .tx_allow_scope import TxAllowScope
@@ -115,7 +113,6 @@ def __init__(
115113 checkpoints : Optional [list [Checkpoint ]] = None ,
116114 rng : Optional [Random ] = None ,
117115 environment_info : Optional [EnvironmentInfo ] = None ,
118- full_verification : bool = False ,
119116 enable_event_queue : bool = False ,
120117 poa_block_producer : PoaBlockProducer | None = None ,
121118 # Websocket factory
@@ -223,10 +220,6 @@ def __init__(
223220 # Thread pool used to resolve pow when sending tokens
224221 self .pow_thread_pool = ThreadPool (minthreads = 0 , maxthreads = settings .MAX_POW_THREADS , name = 'Pow thread pool' )
225222
226- # Full verification execute all validations for transactions and blocks when initializing the node
227- # Can be activated on the command line with --full-verification
228- self ._full_verification = full_verification
229-
230223 # List of whitelisted peers
231224 self .peers_whitelist : list [PeerId ] = []
232225
@@ -272,33 +265,16 @@ def start(self) -> None:
272265 )
273266 sys .exit (- 1 )
274267
275- # If it's a full verification, we save on the storage that we are starting it
276- # this is required because if we stop the initilization in the middle, the metadata
277- # saved on the storage is not reliable anymore, only if we finish it
278- if self ._full_verification :
279- self .tx_storage .start_full_verification ()
280- else :
281- # If it's a fast initialization and the last time a full initialization stopped in the middle
282- # we can't allow the full node to continue, so we need to remove the storage and do a full sync
283- # or execute an initialization with full verification
284- if self .tx_storage .is_running_full_verification ():
285- self .log .error (
286- 'Error initializing node. The last time you started your node you did a full verification '
287- 'that was stopped in the middle. The storage is not reliable anymore and, because of that, '
288- 'you must initialize with a full verification again or remove your storage and do a full sync.'
289- )
290- sys .exit (- 1 )
291-
292- # If self.tx_storage.is_running_manager() is True, the last time the node was running it had a sudden crash
293- # because of that, we must run a full verification because some storage data might be wrong.
294- # The metadata is the only piece of the storage that may be wrong, not the blocks and transactions.
295- if self .tx_storage .is_running_manager ():
296- self .log .error (
297- 'Error initializing node. The last time you executed your full node it wasn\' t stopped correctly. '
298- 'The storage is not reliable anymore and, because of that, so you must run a full verification '
299- 'or remove your storage and do a full sync.'
300- )
301- sys .exit (- 1 )
268+ # If self.tx_storage.is_running_manager() is True, the last time the node was running it had a sudden crash
269+ # because of that, we must run a sync from scratch or from a snapshot.
270+ # The metadata is the only piece of the storage that may be wrong, not the blocks and transactions.
271+ if self .tx_storage .is_running_manager ():
272+ self .log .error (
273+ 'Error initializing node. The last time you executed your full node it wasn\' t stopped correctly. '
274+ 'The storage is not reliable anymore and, because of that you must remove your storage and do a'
275+ 'sync from scratch or from a snapshot.'
276+ )
277+ sys .exit (- 1 )
302278
303279 if self ._enable_event_queue :
304280 self ._event_manager .start (str (self .my_peer .id ))
@@ -312,16 +288,7 @@ def start(self) -> None:
312288 self .tx_storage .disable_lock ()
313289 # Open scope for initialization.
314290 self .tx_storage .set_allow_scope (TxAllowScope .VALID | TxAllowScope .PARTIAL | TxAllowScope .INVALID )
315- # Initialize manager's components.
316- if self ._full_verification :
317- self .tx_storage .reset_indexes ()
318- self ._initialize_components_full_verification ()
319- # Before calling self._initialize_components_full_verification() I start 'full verification' mode and
320- # after that I need to finish it. It's just to know if the full node has stopped a full initialization
321- # in the middle.
322- self .tx_storage .finish_full_verification ()
323- else :
324- self ._initialize_components_new ()
291+ self ._initialize_components ()
325292 self .tx_storage .set_allow_scope (TxAllowScope .VALID )
326293 self .tx_storage .enable_lock ()
327294
@@ -414,159 +381,7 @@ def stop_profiler(self, save_to: Optional[str] = None) -> None:
414381 if save_to :
415382 self .profiler .dump_stats (save_to )
416383
417- def _initialize_components_full_verification (self ) -> None :
418- """You are not supposed to run this method manually. You should run `doStart()` to initialize the
419- manager.
420-
421- This method runs through all transactions, verifying them and updating our wallet.
422- """
423- assert not self ._enable_event_queue , 'this method cannot be used if the events feature is enabled.'
424- assert self ._full_verification
425-
426- self .log .info ('initialize' )
427- if self .wallet :
428- self .wallet ._manually_initialize ()
429- t0 = time .time ()
430- t1 = t0
431- cnt = 0
432- cnt2 = 0
433- t2 = t0
434- h = 0
435-
436- block_count = 0
437- tx_count = 0
438-
439- self .tx_storage .pre_init ()
440- assert self .tx_storage .indexes is not None
441-
442- self ._verify_soft_voided_txs ()
443-
444- # Checkpoints as {height: hash}
445- checkpoint_heights = {}
446- for cp in self .checkpoints :
447- checkpoint_heights [cp .height ] = cp .hash
448-
449- # self.start_profiler()
450- self .log .debug ('reset all metadata' )
451- for tx in self .tx_storage .get_all_transactions ():
452- tx .reset_metadata ()
453-
454- self .log .debug ('load blocks and transactions' )
455- for tx in self .tx_storage ._topological_sort_dfs ():
456- tx_meta = tx .get_metadata ()
457-
458- t2 = time .time ()
459- dt = LogDuration (t2 - t1 )
460- dcnt = cnt - cnt2
461- tx_rate = '?' if dt == 0 else dcnt / dt
462- h = max (h , (tx .static_metadata .height if isinstance (tx , Block ) else 0 ))
463- if dt > 30 :
464- ts_date = datetime .datetime .fromtimestamp (self .tx_storage .latest_timestamp )
465- if h == 0 :
466- self .log .debug ('start loading transactions...' )
467- else :
468- self .log .info ('load transactions...' , tx_rate = tx_rate , tx_new = dcnt , dt = dt ,
469- total = cnt , latest_ts = ts_date , height = h )
470- t1 = t2
471- cnt2 = cnt
472- cnt += 1
473-
474- # It's safe to skip block weight verification during initialization because
475- # we trust the difficulty stored in metadata
476- skip_block_weight_verification = True
477- if block_count % self ._settings .VERIFY_WEIGHT_EVERY_N_BLOCKS == 0 :
478- skip_block_weight_verification = False
479-
480- try :
481- # TODO: deal with invalid tx
482- tx ._update_parents_children_metadata ()
483-
484- if self .tx_storage .can_validate_full (tx ):
485- tx .update_initial_metadata ()
486- if tx .is_genesis :
487- assert tx .validate_checkpoint (self .checkpoints )
488- assert self .verification_service .validate_full (
489- tx ,
490- skip_block_weight_verification = skip_block_weight_verification
491- )
492- self .tx_storage .add_to_indexes (tx )
493- with self .tx_storage .allow_only_valid_context ():
494- self .consensus_algorithm .unsafe_update (tx )
495- self .tx_storage .indexes .update (tx )
496- if self .tx_storage .indexes .mempool_tips is not None :
497- self .tx_storage .indexes .mempool_tips .update (tx ) # XXX: move to indexes.update
498- self .tx_storage .save_transaction (tx , only_metadata = True )
499- else :
500- assert self .verification_service .validate_basic (
501- tx ,
502- skip_block_weight_verification = skip_block_weight_verification
503- )
504- self .tx_storage .save_transaction (tx , only_metadata = True )
505- except (InvalidNewTransaction , TxValidationError ):
506- self .log .error ('unexpected error when initializing' , tx = tx , exc_info = True )
507- raise
508-
509- if tx .is_block :
510- block_count += 1
511-
512- # this works because blocks on the best chain are iterated from lower to higher height
513- assert tx_meta .validation .is_at_least_basic ()
514- assert isinstance (tx , Block )
515- blk_height = tx .get_height ()
516- if not tx_meta .voided_by and tx_meta .validation .is_fully_connected ():
517- # XXX: this might not be needed when making a full init because the consensus should already have
518- self .tx_storage .indexes .height .add_reorg (blk_height , tx .hash , tx .timestamp )
519-
520- # Check if it's a checkpoint block
521- if blk_height in checkpoint_heights :
522- if tx .hash == checkpoint_heights [blk_height ]:
523- del checkpoint_heights [blk_height ]
524- else :
525- # If the hash is different from checkpoint hash, we stop the node
526- self .log .error ('Error initializing the node. Checkpoint validation error.' )
527- sys .exit ()
528- else :
529- tx_count += 1
530-
531- if time .time () - t2 > 1 :
532- dt = LogDuration (time .time () - t2 )
533- self .log .warn ('tx took too long to load' , tx = tx .hash_hex , dt = dt )
534-
535- # we have to have a best_block by now
536- # assert best_block is not None
537-
538- self .tx_storage .indexes ._manually_initialize (self .tx_storage )
539-
540- self .log .debug ('done loading transactions' )
541-
542- # Check if all checkpoints in database are ok
543- my_best_height = self .tx_storage .get_height_best_block ()
544- if checkpoint_heights :
545- # If I have checkpoints that were not validated I must check if they are all in a height I still don't have
546- first = min (list (checkpoint_heights .keys ()))
547- if first <= my_best_height :
548- # If the height of the first checkpoint not validated is lower than the height of the best block
549- # Then it's missing this block
550- self .log .error ('Error initializing the node. Checkpoint validation error.' )
551- sys .exit ()
552-
553- best_height = self .tx_storage .get_height_best_block ()
554- if best_height != h :
555- self .log .warn ('best height doesn\' t match' , best_height = best_height , max_height = h )
556-
557- # self.stop_profiler(save_to='profiles/initializing.prof')
558- self .state = self .NodeState .READY
559-
560- total_load_time = LogDuration (t2 - t0 )
561- tx_rate = '?' if total_load_time == 0 else cnt / total_load_time
562-
563- environment_info = self .environment_info .as_dict () if self .environment_info else {}
564-
565- # Changing the field names in this log could impact log collectors that parse them
566- self .log .info ('ready' , vertex_count = cnt , tx_rate = tx_rate , total_load_time = total_load_time , height = h ,
567- blocks = block_count , txs = tx_count , ** environment_info )
568-
569- def _initialize_components_new (self ) -> None :
384+ def _initialize_components (self ) -> None :
570385 """You are not supposed to run this method manually. You should run `doStart()` to initialize the
571386 manager.
572387
@@ -593,10 +408,6 @@ def _initialize_components_new(self) -> None:
593408 started_at = started_at , last_started_at = last_started_at )
594409
595410 self ._verify_soft_voided_txs ()
596-
597- # TODO: move support for full-verification here, currently we rely on the original _initialize_components
598- # method for full-verification to work, if we implement it here we'll reduce a lot of duplicate and
599- # complex code
600411 self .tx_storage .indexes ._manually_initialize (self .tx_storage )
601412
602413 # Verify if all checkpoints that exist in the database are correct
0 commit comments