@@ -454,9 +454,6 @@ def _initialize_components(self) -> None:
454
454
455
455
self .log .debug ('load blocks and transactions' )
456
456
for tx in self .tx_storage ._topological_sort_dfs ():
457
- if self ._full_verification :
458
- tx .update_initial_metadata ()
459
-
460
457
assert tx .hash is not None
461
458
462
459
tx_meta = tx .get_metadata ()
@@ -486,15 +483,21 @@ def _initialize_components(self) -> None:
486
483
try :
487
484
if self ._full_verification :
488
485
# TODO: deal with invalid tx
486
+ tx .calculate_height ()
487
+ tx ._update_parents_children_metadata ()
488
+
489
489
if tx .can_validate_full ():
490
- self .tx_storage .add_to_indexes (tx )
490
+ tx .calculate_min_height ()
491
+ if tx .is_genesis :
492
+ assert tx .validate_checkpoint (self .checkpoints )
491
493
assert tx .validate_full (skip_block_weight_verification = skip_block_weight_verification )
494
+ self .tx_storage .add_to_indexes (tx )
492
495
self .consensus_algorithm .update (tx )
493
496
self .tx_storage .indexes .update (tx )
494
497
if self .tx_storage .indexes .mempool_tips is not None :
495
498
self .tx_storage .indexes .mempool_tips .update (tx ) # XXX: move to indexes.update
496
499
if self .tx_storage .indexes .deps is not None :
497
- self .sync_v2_step_validations ([tx ])
500
+ self .sync_v2_step_validations ([tx ], quiet = True )
498
501
else :
499
502
assert tx .validate_basic (skip_block_weight_verification = skip_block_weight_verification )
500
503
self .tx_storage .save_transaction (tx , only_metadata = True )
@@ -507,7 +510,9 @@ def _initialize_components(self) -> None:
507
510
assert self .tx_storage .indexes is not None
508
511
if self .tx_storage .indexes .mempool_tips :
509
512
self .tx_storage .indexes .mempool_tips .update (tx )
510
- self .tx_storage .add_to_indexes (tx )
513
+ # XXX: refactor this in the future so the index manager decies whether to update each index
514
+ if tx_meta .validation .is_fully_connected ():
515
+ self .tx_storage .add_to_indexes (tx )
511
516
if tx .is_transaction and tx_meta .voided_by :
512
517
self .tx_storage .del_from_indexes (tx )
513
518
except (InvalidNewTransaction , TxValidationError ):
@@ -562,11 +567,11 @@ def _initialize_components(self) -> None:
562
567
for tx_hash in self .tx_storage .indexes .deps .iter ():
563
568
if not self .tx_storage .transaction_exists (tx_hash ):
564
569
continue
565
- tx = self .tx_storage .get_transaction (tx_hash )
570
+ tx = self .tx_storage .get_transaction (tx_hash , allow_partially_valid = True )
566
571
if tx .get_metadata ().validation .is_final ():
567
572
depended_final_txs .append (tx )
568
573
if self .tx_storage .indexes .deps is not None :
569
- self .sync_v2_step_validations (depended_final_txs )
574
+ self .sync_v2_step_validations (depended_final_txs , quiet = True )
570
575
self .log .debug ('pending validations finished' )
571
576
572
577
best_height = self .tx_storage .get_height_best_block ()
@@ -722,10 +727,10 @@ def _sync_v2_resume_validations(self) -> None:
722
727
for tx_hash in self .tx_storage .indexes .deps .iter ():
723
728
if not self .tx_storage .transaction_exists (tx_hash ):
724
729
continue
725
- tx = self .tx_storage .get_transaction (tx_hash )
730
+ tx = self .tx_storage .get_transaction (tx_hash , allow_partially_valid = True )
726
731
if tx .get_metadata ().validation .is_final ():
727
732
depended_final_txs .append (tx )
728
- self .sync_v2_step_validations (depended_final_txs )
733
+ self .sync_v2_step_validations (depended_final_txs , quiet = True )
729
734
self .log .debug ('pending validations finished' )
730
735
731
736
def add_listen_address (self , addr : str ) -> None :
@@ -1018,7 +1023,7 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
1018
1023
tx .storage = self .tx_storage
1019
1024
1020
1025
try :
1021
- metadata = tx .get_metadata ()
1026
+ metadata = tx .get_metadata (allow_partial = partial )
1022
1027
except TransactionDoesNotExist :
1023
1028
if not fails_silently :
1024
1029
raise InvalidNewTransaction ('missing parent' )
@@ -1061,7 +1066,7 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
1061
1066
self .tx_storage .indexes .update (tx )
1062
1067
if self .tx_storage .indexes .mempool_tips :
1063
1068
self .tx_storage .indexes .mempool_tips .update (tx ) # XXX: move to indexes.update
1064
- self .tx_fully_validated (tx )
1069
+ self .tx_fully_validated (tx , quiet = quiet )
1065
1070
elif sync_checkpoints :
1066
1071
assert self .tx_storage .indexes .deps is not None
1067
1072
metadata .children = self .tx_storage .indexes .deps .known_children (tx )
@@ -1073,7 +1078,10 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
1073
1078
self .log .warn ('on_new_tx(): checkpoint validation failed' , tx = tx .hash_hex , exc_info = True )
1074
1079
return False
1075
1080
self .tx_storage .save_transaction (tx )
1081
+ self .tx_storage .indexes .deps .add_tx (tx )
1082
+ self .log_new_object (tx , 'new {} partially accepted while syncing checkpoints' , quiet = quiet )
1076
1083
else :
1084
+ assert self .tx_storage .indexes .deps is not None
1077
1085
if isinstance (tx , Block ) and not tx .has_basic_block_parent ():
1078
1086
if not fails_silently :
1079
1087
raise InvalidNewTransaction ('block parent needs to be at least basic-valid' )
@@ -1089,38 +1097,33 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
1089
1097
# This needs to be called right before the save because we were adding the children
1090
1098
# in the tx parents even if the tx was invalid (failing the verifications above)
1091
1099
# then I would have a children that was not in the storage
1092
- tx .update_initial_metadata (save = False )
1093
1100
self .tx_storage .save_transaction (tx )
1101
+ self .tx_storage .indexes .deps .add_tx (tx )
1102
+ self .log_new_object (tx , 'new {} partially accepted' , quiet = quiet )
1094
1103
1095
- if tx . is_transaction and self .tx_storage .indexes .deps is not None :
1104
+ if self .tx_storage .indexes .deps is not None :
1096
1105
self .tx_storage .indexes .deps .remove_from_needed_index (tx .hash )
1097
1106
1098
1107
if self .tx_storage .indexes .deps is not None :
1099
1108
try :
1100
- self .sync_v2_step_validations ([tx ])
1109
+ self .sync_v2_step_validations ([tx ], quiet = quiet )
1101
1110
except (AssertionError , HathorError ) as e :
1102
1111
if not fails_silently :
1103
1112
raise InvalidNewTransaction ('step validations failed' ) from e
1104
1113
self .log .warn ('on_new_tx(): step validations failed' , tx = tx .hash_hex , exc_info = True )
1105
1114
return False
1106
1115
1107
- if not quiet :
1108
- ts_date = datetime .datetime .fromtimestamp (tx .timestamp )
1109
- now = datetime .datetime .fromtimestamp (self .reactor .seconds ())
1110
- if tx .is_block :
1111
- self .log .info ('new block' , tx = tx , ts_date = ts_date , time_from_now = tx .get_time_from_now (now ))
1112
- else :
1113
- self .log .info ('new tx' , tx = tx , ts_date = ts_date , time_from_now = tx .get_time_from_now (now ))
1114
-
1115
1116
if propagate_to_peers :
1116
1117
# Propagate to our peers.
1117
1118
self .connections .send_tx_to_peers (tx )
1118
1119
1119
1120
return True
1120
1121
1121
- def sync_v2_step_validations (self , txs : Iterable [BaseTransaction ]) -> None :
1122
+ def sync_v2_step_validations (self , txs : Iterable [BaseTransaction ], * , quiet : bool ) -> None :
1122
1123
""" Step all validations until none can be stepped anymore.
1123
1124
"""
1125
+ from functools import partial
1126
+
1124
1127
assert self .tx_storage .indexes is not None
1125
1128
assert self .tx_storage .indexes .deps is not None
1126
1129
# cur_txs will be empty when there are no more new txs that reached full
@@ -1129,13 +1132,14 @@ def sync_v2_step_validations(self, txs: Iterable[BaseTransaction]) -> None:
1129
1132
assert ready_tx .hash is not None
1130
1133
self .tx_storage .indexes .deps .remove_ready_for_validation (ready_tx .hash )
1131
1134
it_next_ready = self .tx_storage .indexes .deps .next_ready_for_validation (self .tx_storage )
1132
- for tx in map (self .tx_storage .get_transaction , it_next_ready ):
1135
+ get_partially_validated = partial (self .tx_storage .get_transaction , allow_partially_valid = True )
1136
+ for tx in map (get_partially_validated , it_next_ready ):
1133
1137
assert tx .hash is not None
1134
1138
tx .update_initial_metadata ()
1135
1139
try :
1136
1140
# XXX: `reject_locked_reward` might not apply, partial validation is only used on sync-v2
1137
1141
# TODO: deal with `reject_locked_reward` on sync-v2
1138
- assert tx .validate_full (reject_locked_reward = True )
1142
+ assert tx .validate_full (reject_locked_reward = False )
1139
1143
except (AssertionError , HathorError ):
1140
1144
# TODO
1141
1145
raise
@@ -1145,9 +1149,9 @@ def sync_v2_step_validations(self, txs: Iterable[BaseTransaction]) -> None:
1145
1149
self .tx_storage .indexes .update (tx )
1146
1150
if self .tx_storage .indexes .mempool_tips :
1147
1151
self .tx_storage .indexes .mempool_tips .update (tx ) # XXX: move to indexes.update
1148
- self .tx_fully_validated (tx )
1152
+ self .tx_fully_validated (tx , quiet = quiet )
1149
1153
1150
- def tx_fully_validated (self , tx : BaseTransaction ) -> None :
1154
+ def tx_fully_validated (self , tx : BaseTransaction , * , quiet : bool ) -> None :
1151
1155
""" Handle operations that need to happen once the tx becomes fully validated.
1152
1156
1153
1157
This might happen immediately after we receive the tx, if we have all dependencies
@@ -1166,6 +1170,30 @@ def tx_fully_validated(self, tx: BaseTransaction) -> None:
1166
1170
# TODO Remove it and use pubsub instead.
1167
1171
self .wallet .on_new_tx (tx )
1168
1172
1173
+ self .log_new_object (tx , 'new {}' , quiet = quiet )
1174
+
1175
+ def log_new_object (self , tx : BaseTransaction , message_fmt : str , * , quiet : bool ) -> None :
1176
+ """ A shortcut for logging additional information for block/txs.
1177
+ """
1178
+ metadata = tx .get_metadata ()
1179
+ now = datetime .datetime .fromtimestamp (self .reactor .seconds ())
1180
+ kwargs = {
1181
+ 'tx' : tx ,
1182
+ 'ts_date' : datetime .datetime .fromtimestamp (tx .timestamp ),
1183
+ 'time_from_now' : tx .get_time_from_now (now ),
1184
+ 'validation' : metadata .validation .name ,
1185
+ }
1186
+ if tx .is_block :
1187
+ message = message_fmt .format ('block' )
1188
+ kwargs ['height' ] = metadata .get_soft_height ()
1189
+ else :
1190
+ message = message_fmt .format ('tx' )
1191
+ if not quiet :
1192
+ log_func = self .log .info
1193
+ else :
1194
+ log_func = self .log .debug
1195
+ log_func (message , ** kwargs )
1196
+
1169
1197
def listen (self , description : str , use_ssl : Optional [bool ] = None ) -> None :
1170
1198
endpoint = self .connections .listen (description , use_ssl )
1171
1199
# XXX: endpoint: IStreamServerEndpoint does not intrinsically have a port, but in practice all concrete cases
0 commit comments