Browse Source

lnpeer: warnings for shutdown and open_channel

patch-4
bitromortac 3 years ago
committed by ThomasV
parent
commit
3915045067
  1. 10
      electrum/lnchannel.py
  2. 27
      electrum/lnpeer.py
  3. 1
      electrum/lnutil.py
  4. 5
      electrum/tests/test_lnpeer.py

10
electrum/lnchannel.py

@ -53,7 +53,7 @@ from .lnutil import (Outpoint, LocalConfig, RemoteConfig, Keypair, OnlyPubkeyKey
ShortChannelID, map_htlcs_to_ctx_output_idxs, LNPeerAddr,
fee_for_htlc_output, offered_htlc_trim_threshold_sat,
received_htlc_trim_threshold_sat, make_commitment_output_to_remote_address,
ChannelType)
ChannelType, LNProtocolWarning)
from .lnsweep import create_sweeptxs_for_our_ctx, create_sweeptxs_for_their_ctx
from .lnsweep import create_sweeptx_for_their_revoked_htlc, SweepInfo
from .lnhtlc import HTLCManager
@ -981,7 +981,9 @@ class Channel(AbstractChannel):
preimage_hex = pending_local_commitment.serialize_preimage(0)
pre_hash = sha256d(bfh(preimage_hex))
if not ecc.verify_signature(self.config[REMOTE].multisig_key.pubkey, sig, pre_hash):
raise Exception(f'failed verifying signature of our updated commitment transaction: {bh2u(sig)} preimage is {preimage_hex}')
raise LNProtocolWarning(
f'failed verifying signature of our updated commitment transaction: '
f'{bh2u(sig)} preimage is {preimage_hex}, rawtx: {pending_local_commitment.serialize()}')
htlc_sigs_string = b''.join(htlc_sigs)
@ -993,7 +995,7 @@ class Channel(AbstractChannel):
subject=LOCAL,
ctn=next_local_ctn)
if len(htlc_to_ctx_output_idx_map) != len(htlc_sigs):
raise Exception(f'htlc sigs failure. recv {len(htlc_sigs)} sigs, expected {len(htlc_to_ctx_output_idx_map)}')
raise LNProtocolWarning(f'htlc sigs failure. recv {len(htlc_sigs)} sigs, expected {len(htlc_to_ctx_output_idx_map)}')
for (direction, htlc), (ctx_output_idx, htlc_relative_idx) in htlc_to_ctx_output_idx_map.items():
htlc_sig = htlc_sigs[htlc_relative_idx]
self._verify_htlc_sig(htlc=htlc,
@ -1021,7 +1023,7 @@ class Channel(AbstractChannel):
pre_hash = sha256d(bfh(htlc_tx.serialize_preimage(0)))
remote_htlc_pubkey = derive_pubkey(self.config[REMOTE].htlc_basepoint.pubkey, pcp)
if not ecc.verify_signature(remote_htlc_pubkey, htlc_sig, pre_hash):
raise Exception(f'failed verifying HTLC signatures: {htlc} {htlc_direction}')
raise LNProtocolWarning(f'failed verifying HTLC signatures: {htlc} {htlc_direction}, rawtx: {htlc_tx.serialize()}')
def get_remote_htlc_sig_for_htlc(self, *, htlc_relative_idx: int) -> bytes:
data = self.config[LOCAL].current_htlc_signatures

27
electrum/lnpeer.py

@ -42,7 +42,7 @@ from .lnutil import (Outpoint, LocalConfig, RECEIVED, UpdateAddHtlc, ChannelConf
LightningPeerConnectionClosed, HandshakeFailed,
RemoteMisbehaving, ShortChannelID,
IncompatibleLightningFeatures, derive_payment_secret_from_payment_preimage,
UpfrontShutdownScriptViolation, ChannelType)
ChannelType, LNProtocolWarning)
from .lnutil import FeeUpdate, channel_id_from_funding_tx
from .lntransport import LNTransport, LNTransportBase
from .lnmsg import encode_msg, decode_msg, UnknownOptionalMsgType
@ -861,7 +861,10 @@ class Peer(Logger):
payload = await self.wait_for_message('funding_signed', channel_id)
self.logger.info('received funding_signed')
remote_sig = payload['signature']
chan.receive_new_commitment(remote_sig, [])
try:
chan.receive_new_commitment(remote_sig, [])
except LNProtocolWarning as e:
await self.send_warning(channel_id, message=str(e), close_connection=True)
chan.open_with_first_pcp(remote_per_commitment_point, remote_sig)
chan.set_state(ChannelState.OPENING)
self.lnworker.add_new_channel(chan)
@ -1020,7 +1023,10 @@ class Peer(Logger):
if isinstance(self.transport, LNTransport):
chan.add_or_update_peer_addr(self.transport.peer_addr)
remote_sig = funding_created['signature']
chan.receive_new_commitment(remote_sig, [])
try:
chan.receive_new_commitment(remote_sig, [])
except LNProtocolWarning as e:
await self.send_warning(channel_id, message=str(e), close_connection=True)
sig_64, _ = chan.sign_next_commitment()
self.send_message('funding_signed',
channel_id=channel_id,
@ -1868,12 +1874,18 @@ class Peer(Logger):
return txid
async def on_shutdown(self, chan: Channel, payload):
# TODO: A receiving node: if it hasn't received a funding_signed (if it is a
# funder) or a funding_created (if it is a fundee):
# SHOULD send an error and fail the channel.
their_scriptpubkey = payload['scriptpubkey']
their_upfront_scriptpubkey = chan.config[REMOTE].upfront_shutdown_script
# BOLT-02 check if they use the upfront shutdown script they advertized
if their_upfront_scriptpubkey:
if self.is_upfront_shutdown_script() and their_upfront_scriptpubkey:
if not (their_scriptpubkey == their_upfront_scriptpubkey):
raise UpfrontShutdownScriptViolation("remote didn't use upfront shutdown script it commited to in channel opening")
await self.send_warning(
chan.channel_id,
"remote didn't use upfront shutdown script it commited to in channel opening",
close_connection=True)
else:
# BOLT-02 restrict the scriptpubkey to some templates:
if self.is_shutdown_anysegwit() and match_script_against_template(their_scriptpubkey, transaction.SCRIPTPUBKEY_TEMPLATE_ANYSEGWIT):
@ -1881,7 +1893,10 @@ class Peer(Logger):
elif match_script_against_template(their_scriptpubkey, transaction.SCRIPTPUBKEY_TEMPLATE_WITNESS_V0):
pass
else:
raise Exception(f'scriptpubkey in received shutdown message does not conform to any template: {their_scriptpubkey.hex()}')
await self.send_warning(
chan.channel_id,
f'scriptpubkey in received shutdown message does not conform to any template: {their_scriptpubkey.hex()}',
close_connection=True)
chan_id = chan.channel_id
if chan_id in self.shutdown_received:

1
electrum/lnutil.py

@ -351,7 +351,6 @@ class UnableToDeriveSecret(LightningError): pass
class HandshakeFailed(LightningError): pass
class ConnStringFormatError(LightningError): pass
class RemoteMisbehaving(LightningError): pass
class UpfrontShutdownScriptViolation(RemoteMisbehaving): pass
class NotFoundChanAnnouncementForUpdate(Exception): pass
class InvalidGossipMsg(Exception):

5
electrum/tests/test_lnpeer.py

@ -22,9 +22,8 @@ from electrum import simple_config, lnutil
from electrum.lnaddr import lnencode, LnAddr, lndecode
from electrum.bitcoin import COIN, sha256
from electrum.util import bh2u, create_and_start_event_loop, NetworkRetryManager, bfh, OldTaskGroup
from electrum.lnpeer import Peer, UpfrontShutdownScriptViolation
from electrum.lnpeer import Peer
from electrum.lnutil import LNPeerAddr, Keypair, privkey_to_pubkey
from electrum.lnutil import LightningPeerConnectionClosed, RemoteMisbehaving
from electrum.lnutil import PaymentFailure, LnFeatures, HTLCOwner
from electrum.lnchannel import ChannelState, PeerState, Channel
from electrum.lnrouter import LNPathFinder, PathEdge, LNPathInconsistent
@ -1201,7 +1200,7 @@ class TestPeer(TestCaseForTestnet):
gath = asyncio.gather(*coros)
await gath
with self.assertRaises(UpfrontShutdownScriptViolation):
with self.assertRaises(GracefulDisconnect):
run(test())
# bob sends the same upfront_shutdown_script has he announced

Loading…
Cancel
Save