Browse Source

lnonion: use IntEnum and IntFlag for failure codes

regtest_lnd
SomberNight 6 years ago
parent
commit
f3bb66d258
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 11
      electrum/lnbase.py
  2. 70
      electrum/lnonion.py

11
electrum/lnbase.py

@ -25,7 +25,7 @@ from .crypto import sha256
from . import constants from . import constants
from .util import PrintError, bh2u, print_error, bfh, log_exceptions from .util import PrintError, bh2u, print_error, bfh, log_exceptions
from .transaction import Transaction, TxOutput from .transaction import Transaction, TxOutput
from .lnonion import new_onion_packet, OnionHopsDataSingle, OnionPerHop, decode_onion_error, ONION_FAILURE_CODE_MAP from .lnonion import new_onion_packet, OnionHopsDataSingle, OnionPerHop, decode_onion_error, OnionFailureCode
from .lnaddr import lndecode from .lnaddr import lndecode
from .lnhtlc import HTLCStateMachine, RevokeAndAck from .lnhtlc import HTLCStateMachine, RevokeAndAck
from .lnutil import (Outpoint, ChannelConfig, LocalState, from .lnutil import (Outpoint, ChannelConfig, LocalState,
@ -467,9 +467,12 @@ class Peer(PrintError):
# Note that this is prone to a race.. we might not have a short_channel_id # Note that this is prone to a race.. we might not have a short_channel_id
# associated with the channel in some cases # associated with the channel in some cases
short_channel_id = payload['short_channel_id'] short_channel_id = payload['short_channel_id']
self.print_error("not found channel announce for channel update in db", bh2u(short_channel_id))
for chan in self.channels.values(): for chan in self.channels.values():
if chan.short_channel_id_predicted == short_channel_id: if chan.short_channel_id_predicted == short_channel_id:
chan.pending_channel_update_message = payload chan.pending_channel_update_message = payload
self.print_error("channel update is for our own private channel", bh2u(short_channel_id))
break
def on_channel_announcement(self, payload): def on_channel_announcement(self, payload):
self.channel_db.on_channel_announcement(payload) self.channel_db.on_channel_announcement(payload)
@ -1022,10 +1025,9 @@ class Peer(PrintError):
self.print_error("UPDATE_FAIL_HTLC. cannot decode! attempted route is MISSING. {}".format(key)) self.print_error("UPDATE_FAIL_HTLC. cannot decode! attempted route is MISSING. {}".format(key))
else: else:
failure_msg, sender_idx = decode_onion_error(payload["reason"], [x.node_id for x in route], chan.onion_keys[htlc_id]) failure_msg, sender_idx = decode_onion_error(payload["reason"], [x.node_id for x in route], chan.onion_keys[htlc_id])
code = failure_msg.code code = OnionFailureCode(failure_msg.code)
code_name = ONION_FAILURE_CODE_MAP.get(code, 'unknown_error??')
data = failure_msg.data data = failure_msg.data
self.print_error("UPDATE_FAIL_HTLC", code_name, code, data) self.print_error("UPDATE_FAIL_HTLC", repr(code), data)
try: try:
short_chan_id = route[sender_idx + 1].short_channel_id short_chan_id = route[sender_idx + 1].short_channel_id
except IndexError: except IndexError:
@ -1034,7 +1036,6 @@ class Peer(PrintError):
# TODO this should depend on the error # TODO this should depend on the error
# also, we need finer blacklisting (directed edges; nodes) # also, we need finer blacklisting (directed edges; nodes)
self.network.path_finder.blacklist.add(short_chan_id) self.network.path_finder.blacklist.add(short_chan_id)
self.print_error("HTLC failure with code {} ({})".format(code, code_name))
# process update_fail_htlc on channel # process update_fail_htlc on channel
chan = self.channels[channel_id] chan = self.channels[channel_id]
chan.receive_fail_htlc(htlc_id) chan.receive_fail_htlc(htlc_id)

70
electrum/lnonion.py

@ -27,6 +27,7 @@ import hashlib
import hmac import hmac
from collections import namedtuple from collections import namedtuple
from typing import Sequence from typing import Sequence
from enum import IntEnum, IntFlag
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms from cryptography.hazmat.primitives.ciphers import Cipher, algorithms
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
@ -299,33 +300,46 @@ def get_failure_msg_from_onion_error(decrypted_error_packet: bytes) -> OnionRout
return OnionRoutingFailureMessage(failure_code, failure_data) return OnionRoutingFailureMessage(failure_code, failure_data)
ONION_FC_BADONION = BADONION = 0x8000 class OnionFailureCodeMetaFlag(IntFlag):
ONION_FC_PERM = PERM = 0x4000 BADONION = 0x8000
ONION_FC_NODE = NODE = 0x2000 PERM = 0x4000
ONION_FC_UPDATE = UPDATE = 0x1000 NODE = 0x2000
ONION_FAILURE_CODE_MAP = { UPDATE = 0x1000
PERM | 1 : 'invalid_realm',
NODE | 2 : 'temporary_node_failure', BADONION = OnionFailureCodeMetaFlag.BADONION
PERM | NODE | 2 : 'permanent_node_failure', PERM = OnionFailureCodeMetaFlag.PERM
PERM | NODE | 3 : 'required_node_feature_missing', NODE = OnionFailureCodeMetaFlag.NODE
BADONION | PERM | 4 : 'invalid_onion_version', UPDATE = OnionFailureCodeMetaFlag.UPDATE
BADONION | PERM | 5 : 'invalid_onion_hmac', class OnionFailureCode(IntEnum):
BADONION | PERM | 6 : 'invalid_onion_key', INVALID_REALM = PERM | 1
UPDATE | 7 : 'temporary_channel_failure', TEMPORARY_NODE_FAILURE = NODE | 2
PERM | 8 : 'permanent_channel_failure', PERMANENT_NODE_FAILURE = PERM | NODE | 2
PERM | 9 : 'required_channel_feature_missing', REQUIRED_NODE_FEATURE_MISSING = PERM | NODE | 3
PERM | 10 : 'unknown_next_peer', INVALID_ONION_VERSION = BADONION | PERM | 4
UPDATE | 11 : 'amount_below_minimum', INVALID_ONION_HMAC = BADONION | PERM | 5
UPDATE | 12 : 'fee_insufficient', INVALID_ONION_KEY = BADONION | PERM | 6
UPDATE | 13 : 'incorrect_cltv_expiry', TEMPORARY_CHANNEL_FAILURE = UPDATE | 7
UPDATE | 14 : 'expiry_too_soon', PERMANENT_CHANNEL_FAILURE = PERM | 8
PERM | 15 : 'unknown_payment_hash', REQUIRED_CHANNEL_FEATURE_MISSING = PERM | 9
PERM | 16 : 'incorrect_payment_amount', UNKNOWN_NEXT_PEER = PERM | 10
17 : 'final_expiry_too_soon', AMOUNT_BELOW_MINIMUM = UPDATE | 11
18 : 'final_incorrect_cltv_expiry', FEE_INSUFFICIENT = UPDATE | 12
19 : 'final_incorrect_htlc_amount', INCORRECT_CLTV_EXPIRY = UPDATE | 13
UPDATE | 20 : 'channel_disabled', EXPIRY_TOO_SOON = UPDATE | 14
21 : 'expiry_too_far', UNKNOWN_PAYMENT_HASH = PERM | 15
} INCORRECT_PAYMENT_AMOUNT = PERM | 16
FINAL_EXPIRY_TOO_SOON = 17
FINAL_INCORRECT_CLTV_EXPIRY = 18
FINAL_INCORRECT_HTLC_AMOUNT = 19
CHANNEL_DISABLED = UPDATE | 20
EXPIRY_TOO_FAR = 21
@classmethod
def _missing_(cls, value: int) -> int:
# note that for unknown error codes, we return an int,
# not an instance of cls
return value
# don't use these elsewhere, the names are ambiguous without context # don't use these elsewhere, the names are ambiguous without context
del BADONION; del PERM; del NODE; del UPDATE del BADONION; del PERM; del NODE; del UPDATE

Loading…
Cancel
Save