@@ -442,9 +442,6 @@ def _initialize_components(self) -> None:
442
442
443
443
self .log .debug ('load blocks and transactions' )
444
444
for tx in self .tx_storage ._topological_sort_dfs ():
445
- if self ._full_verification :
446
- tx .update_initial_metadata ()
447
-
448
445
assert tx .hash is not None
449
446
450
447
tx_meta = tx .get_metadata ()
@@ -474,15 +471,21 @@ def _initialize_components(self) -> None:
474
471
try :
475
472
if self ._full_verification :
476
473
# TODO: deal with invalid tx
474
+ tx .calculate_height ()
475
+ tx ._update_parents_children_metadata ()
476
+
477
477
if tx .can_validate_full ():
478
- self .tx_storage .add_to_indexes (tx )
478
+ tx .calculate_min_height ()
479
+ if tx .is_genesis :
480
+ assert tx .validate_checkpoint (self .checkpoints )
479
481
assert tx .validate_full (skip_block_weight_verification = skip_block_weight_verification )
482
+ self .tx_storage .add_to_indexes (tx )
480
483
self .consensus_algorithm .update (tx )
481
484
self .tx_storage .indexes .update (tx )
482
485
if self .tx_storage .indexes .mempool_tips is not None :
483
486
self .tx_storage .indexes .mempool_tips .update (tx ) # XXX: move to indexes.update
484
487
if self .tx_storage .indexes .deps is not None :
485
- self .sync_v2_step_validations ([tx ])
488
+ self .sync_v2_step_validations ([tx ], quiet = True )
486
489
else :
487
490
assert tx .validate_basic (skip_block_weight_verification = skip_block_weight_verification )
488
491
self .tx_storage .save_transaction (tx , only_metadata = True )
@@ -495,7 +498,9 @@ def _initialize_components(self) -> None:
495
498
assert self .tx_storage .indexes is not None
496
499
if self .tx_storage .indexes .mempool_tips :
497
500
self .tx_storage .indexes .mempool_tips .update (tx )
498
- self .tx_storage .add_to_indexes (tx )
501
+ # XXX: refactor this in the future so the index manager decies whether to update each index
502
+ if tx_meta .validation .is_fully_connected ():
503
+ self .tx_storage .add_to_indexes (tx )
499
504
if tx .is_transaction and tx_meta .voided_by :
500
505
self .tx_storage .del_from_indexes (tx )
501
506
except (InvalidNewTransaction , TxValidationError ):
@@ -550,11 +555,11 @@ def _initialize_components(self) -> None:
550
555
for tx_hash in self .tx_storage .indexes .deps .iter ():
551
556
if not self .tx_storage .transaction_exists (tx_hash ):
552
557
continue
553
- tx = self .tx_storage .get_transaction (tx_hash )
558
+ tx = self .tx_storage .get_transaction (tx_hash , allow_partially_valid = True )
554
559
if tx .get_metadata ().validation .is_final ():
555
560
depended_final_txs .append (tx )
556
561
if self .tx_storage .indexes .deps is not None :
557
- self .sync_v2_step_validations (depended_final_txs )
562
+ self .sync_v2_step_validations (depended_final_txs , quiet = True )
558
563
self .log .debug ('pending validations finished' )
559
564
560
565
best_height = self .tx_storage .get_height_best_block ()
@@ -705,10 +710,10 @@ def _sync_v2_resume_validations(self) -> None:
705
710
for tx_hash in self .tx_storage .indexes .deps .iter ():
706
711
if not self .tx_storage .transaction_exists (tx_hash ):
707
712
continue
708
- tx = self .tx_storage .get_transaction (tx_hash )
713
+ tx = self .tx_storage .get_transaction (tx_hash , allow_partially_valid = True )
709
714
if tx .get_metadata ().validation .is_final ():
710
715
depended_final_txs .append (tx )
711
- self .sync_v2_step_validations (depended_final_txs )
716
+ self .sync_v2_step_validations (depended_final_txs , quiet = True )
712
717
self .log .debug ('pending validations finished' )
713
718
714
719
def add_listen_address (self , addr : str ) -> None :
@@ -1001,7 +1006,7 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
1001
1006
tx .storage = self .tx_storage
1002
1007
1003
1008
try :
1004
- metadata = tx .get_metadata ()
1009
+ metadata = tx .get_metadata (allow_partial = partial )
1005
1010
except TransactionDoesNotExist :
1006
1011
if not fails_silently :
1007
1012
raise InvalidNewTransaction ('missing parent' )
@@ -1044,7 +1049,7 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
1044
1049
self .tx_storage .indexes .update (tx )
1045
1050
if self .tx_storage .indexes .mempool_tips :
1046
1051
self .tx_storage .indexes .mempool_tips .update (tx ) # XXX: move to indexes.update
1047
- self .tx_fully_validated (tx )
1052
+ self .tx_fully_validated (tx , quiet = quiet )
1048
1053
elif sync_checkpoints :
1049
1054
assert self .tx_storage .indexes .deps is not None
1050
1055
metadata .children = self .tx_storage .indexes .deps .known_children (tx )
@@ -1056,7 +1061,10 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
1056
1061
self .log .warn ('on_new_tx(): checkpoint validation failed' , tx = tx .hash_hex , exc_info = True )
1057
1062
return False
1058
1063
self .tx_storage .save_transaction (tx )
1064
+ self .tx_storage .indexes .deps .add_tx (tx )
1065
+ self .log_new_object (tx , 'new {} partially accepted while syncing checkpoints' , quiet = quiet )
1059
1066
else :
1067
+ assert self .tx_storage .indexes .deps is not None
1060
1068
if isinstance (tx , Block ) and not tx .has_basic_block_parent ():
1061
1069
if not fails_silently :
1062
1070
raise InvalidNewTransaction ('block parent needs to be at least basic-valid' )
@@ -1072,38 +1080,33 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
1072
1080
# This needs to be called right before the save because we were adding the children
1073
1081
# in the tx parents even if the tx was invalid (failing the verifications above)
1074
1082
# then I would have a children that was not in the storage
1075
- tx .update_initial_metadata (save = False )
1076
1083
self .tx_storage .save_transaction (tx )
1084
+ self .tx_storage .indexes .deps .add_tx (tx )
1085
+ self .log_new_object (tx , 'new {} partially accepted' , quiet = quiet )
1077
1086
1078
- if tx . is_transaction and self .tx_storage .indexes .deps is not None :
1087
+ if self .tx_storage .indexes .deps is not None :
1079
1088
self .tx_storage .indexes .deps .remove_from_needed_index (tx .hash )
1080
1089
1081
1090
if self .tx_storage .indexes .deps is not None :
1082
1091
try :
1083
- self .sync_v2_step_validations ([tx ])
1092
+ self .sync_v2_step_validations ([tx ], quiet = quiet )
1084
1093
except (AssertionError , HathorError ) as e :
1085
1094
if not fails_silently :
1086
1095
raise InvalidNewTransaction ('step validations failed' ) from e
1087
1096
self .log .warn ('on_new_tx(): step validations failed' , tx = tx .hash_hex , exc_info = True )
1088
1097
return False
1089
1098
1090
- if not quiet :
1091
- ts_date = datetime .datetime .fromtimestamp (tx .timestamp )
1092
- now = datetime .datetime .fromtimestamp (self .reactor .seconds ())
1093
- if tx .is_block :
1094
- self .log .info ('new block' , tx = tx , ts_date = ts_date , time_from_now = tx .get_time_from_now (now ))
1095
- else :
1096
- self .log .info ('new tx' , tx = tx , ts_date = ts_date , time_from_now = tx .get_time_from_now (now ))
1097
-
1098
1099
if propagate_to_peers :
1099
1100
# Propagate to our peers.
1100
1101
self .connections .send_tx_to_peers (tx )
1101
1102
1102
1103
return True
1103
1104
1104
- def sync_v2_step_validations (self , txs : Iterable [BaseTransaction ]) -> None :
1105
+ def sync_v2_step_validations (self , txs : Iterable [BaseTransaction ], * , quiet : bool ) -> None :
1105
1106
""" Step all validations until none can be stepped anymore.
1106
1107
"""
1108
+ from functools import partial
1109
+
1107
1110
assert self .tx_storage .indexes is not None
1108
1111
assert self .tx_storage .indexes .deps is not None
1109
1112
# cur_txs will be empty when there are no more new txs that reached full
@@ -1112,13 +1115,14 @@ def sync_v2_step_validations(self, txs: Iterable[BaseTransaction]) -> None:
1112
1115
assert ready_tx .hash is not None
1113
1116
self .tx_storage .indexes .deps .remove_ready_for_validation (ready_tx .hash )
1114
1117
it_next_ready = self .tx_storage .indexes .deps .next_ready_for_validation (self .tx_storage )
1115
- for tx in map (self .tx_storage .get_transaction , it_next_ready ):
1118
+ get_partially_validated = partial (self .tx_storage .get_transaction , allow_partially_valid = True )
1119
+ for tx in map (get_partially_validated , it_next_ready ):
1116
1120
assert tx .hash is not None
1117
1121
tx .update_initial_metadata ()
1118
1122
try :
1119
1123
# XXX: `reject_locked_reward` might not apply, partial validation is only used on sync-v2
1120
1124
# TODO: deal with `reject_locked_reward` on sync-v2
1121
- assert tx .validate_full (reject_locked_reward = True )
1125
+ assert tx .validate_full (reject_locked_reward = False )
1122
1126
except (AssertionError , HathorError ):
1123
1127
# TODO
1124
1128
raise
@@ -1128,9 +1132,9 @@ def sync_v2_step_validations(self, txs: Iterable[BaseTransaction]) -> None:
1128
1132
self .tx_storage .indexes .update (tx )
1129
1133
if self .tx_storage .indexes .mempool_tips :
1130
1134
self .tx_storage .indexes .mempool_tips .update (tx ) # XXX: move to indexes.update
1131
- self .tx_fully_validated (tx )
1135
+ self .tx_fully_validated (tx , quiet = quiet )
1132
1136
1133
- def tx_fully_validated (self , tx : BaseTransaction ) -> None :
1137
+ def tx_fully_validated (self , tx : BaseTransaction , * , quiet : bool ) -> None :
1134
1138
""" Handle operations that need to happen once the tx becomes fully validated.
1135
1139
1136
1140
This might happen immediately after we receive the tx, if we have all dependencies
@@ -1149,6 +1153,30 @@ def tx_fully_validated(self, tx: BaseTransaction) -> None:
1149
1153
# TODO Remove it and use pubsub instead.
1150
1154
self .wallet .on_new_tx (tx )
1151
1155
1156
+ self .log_new_object (tx , 'new {}' , quiet = quiet )
1157
+
1158
+ def log_new_object (self , tx : BaseTransaction , message_fmt : str , * , quiet : bool ) -> None :
1159
+ """ A shortcut for logging additional information for block/txs.
1160
+ """
1161
+ metadata = tx .get_metadata ()
1162
+ now = datetime .datetime .fromtimestamp (self .reactor .seconds ())
1163
+ kwargs = {
1164
+ 'tx' : tx ,
1165
+ 'ts_date' : datetime .datetime .fromtimestamp (tx .timestamp ),
1166
+ 'time_from_now' : tx .get_time_from_now (now ),
1167
+ 'validation' : metadata .validation .name ,
1168
+ }
1169
+ if tx .is_block :
1170
+ message = message_fmt .format ('block' )
1171
+ kwargs ['height' ] = metadata .get_soft_height ()
1172
+ else :
1173
+ message = message_fmt .format ('tx' )
1174
+ if not quiet :
1175
+ log_func = self .log .info
1176
+ else :
1177
+ log_func = self .log .debug
1178
+ log_func (message , ** kwargs )
1179
+
1152
1180
def listen (self , description : str , use_ssl : Optional [bool ] = None ) -> None :
1153
1181
endpoint = self .connections .listen (description , use_ssl )
1154
1182
# XXX: endpoint: IStreamServerEndpoint does not intrinsically have a port, but in practice all concrete cases
0 commit comments