Skip to content

Commit bd220e7

Browse files
committed
feat(unrecoverable-error): implement halting of full node execution
1 parent 67085e3 commit bd220e7

File tree

4 files changed

+13
-23
lines changed

4 files changed

+13
-23
lines changed

hathor/conf/settings.py

-3
Original file line numberDiff line numberDiff line change
@@ -389,9 +389,6 @@ def GENESIS_TX2_TIMESTAMP(self) -> int:
389389
# Identifier used in metadata's voided_by to mark a tx as soft-voided.
390390
SOFT_VOIDED_ID: bytes = b'tx-non-grata'
391391

392-
# Identifier used in metadata's voided_by when an unexpected exception occurs at consensus.
393-
CONSENSUS_FAIL_ID: bytes = b'consensus-fail'
394-
395392
# Identifier used in metadata's voided_by to mark a tx as partially validated.
396393
PARTIALLY_VALIDATED_ID: bytes = b'pending-validation'
397394

hathor/consensus/consensus.py

+7-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
import os
1415

1516
from structlog import get_logger
1617

@@ -76,10 +77,12 @@ def update(self, base: BaseTransaction) -> None:
7677
try:
7778
self._unsafe_update(base)
7879
except Exception:
79-
meta.add_voided_by(self._settings.CONSENSUS_FAIL_ID)
80-
assert base.storage is not None
81-
base.storage.save_transaction(base, only_metadata=True)
82-
raise
80+
self.log.critical(
81+
'Consensus update failed, causing the full node to halt execution. Manual intervention is required.',
82+
tx=base.hash_hex,
83+
exc_info=True
84+
)
85+
os._exit(-1)
8386

8487
def _unsafe_update(self, base: BaseTransaction) -> None:
8588
"""Run a consensus update with its own context, indexes will be updated accordingly."""
@@ -154,8 +157,6 @@ def filter_out_soft_voided_entries(self, tx: BaseTransaction, voided_by: set[byt
154157
for h in voided_by:
155158
if h == self._settings.SOFT_VOIDED_ID:
156159
continue
157-
if h == self._settings.CONSENSUS_FAIL_ID:
158-
continue
159160
if h == tx.hash:
160161
continue
161162
if h in self.soft_voided_tx_ids:

hathor/manager.py

+1-7
Original file line numberDiff line numberDiff line change
@@ -1003,13 +1003,7 @@ def on_new_tx(self, tx: BaseTransaction, *, conn: Optional[HathorProtocol] = Non
10031003
tx.update_initial_metadata(save=False)
10041004
self.tx_storage.save_transaction(tx)
10051005
self.tx_storage.add_to_indexes(tx)
1006-
try:
1007-
self.consensus_algorithm.update(tx)
1008-
except HathorError as e:
1009-
if not fails_silently:
1010-
raise InvalidNewTransaction('consensus update failed') from e
1011-
self.log.warn('on_new_tx(): consensus update failed', tx=tx.hash_hex, exc_info=True)
1012-
return False
1006+
self.consensus_algorithm.update(tx)
10131007

10141008
assert self.verification_service.validate_full(
10151009
tx,

tests/consensus/test_consensus.py

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from unittest.mock import MagicMock
1+
import os
2+
from unittest.mock import MagicMock, patch
23

34
from hathor.conf import HathorSettings
45
from hathor.transaction.storage import TransactionMemoryStorage
@@ -25,7 +26,7 @@ def setUp(self):
2526
self.genesis_blocks = [tx for tx in self.genesis if tx.is_block]
2627
self.genesis_txs = [tx for tx in self.genesis if not tx.is_block]
2728

28-
def test_unhandled_exception(self):
29+
def test_unhandled_exception(self) -> None:
2930
manager = self.create_peer('testnet', tx_storage=self.tx_storage)
3031

3132
# Mine a few blocks in a row with no transaction but the genesis
@@ -41,12 +42,9 @@ class MyError(Exception):
4142

4243
manager.consensus_algorithm._unsafe_update = MagicMock(side_effect=MyError)
4344

44-
with self.assertRaises(MyError):
45+
with patch.object(os, '_exit') as exit_mock:
4546
manager.propagate_tx(tx, fails_silently=False)
46-
47-
tx2 = manager.tx_storage.get_transaction(tx.hash)
48-
meta2 = tx2.get_metadata()
49-
self.assertEqual({settings.CONSENSUS_FAIL_ID}, meta2.voided_by)
47+
exit_mock.assert_called_once_with(-1)
5048

5149
def test_revert_block_high_weight(self):
5250
""" A conflict transaction will be propagated. At first, it will be voided.

0 commit comments

Comments
 (0)