Skip to content

Commit b00296e

Browse files
committed
create_channel_storage: return dict instead of StoredDict
we should avoid dangling StoredDict; this does not make sense if the DB is not in memory.
1 parent 1f4c0fc commit b00296e

5 files changed

Lines changed: 27 additions & 12 deletions

File tree

electrum/lnchannel.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
Iterable, Sequence, TYPE_CHECKING, Iterator, Union, Mapping)
2727
from abc import ABC, abstractmethod
2828
import itertools
29+
import threading
2930

3031
from aiorpcx import NetAddress
3132

@@ -790,7 +791,7 @@ def __init__(
790791
Logger.__init__(self) # should be after short_channel_id is set
791792
self.lnworker = lnworker
792793
self.storage = state
793-
self.db_lock = self.storage.lock
794+
self.db_lock = threading.RLock() if type(self.storage) is dict else self.storage.lock
794795
self.config = {}
795796
self.config[LOCAL] = state["local_config"]
796797
self.config[REMOTE] = state["remote_config"]
@@ -799,7 +800,7 @@ def __init__(
799800
self.node_id = bfh(state["node_id"])
800801
self.onion_keys = state['onion_keys'] # type: Dict[int, bytes]
801802
self.data_loss_protect_remote_pcp = state['data_loss_protect_remote_pcp']
802-
self.hm = HTLCManager(log=state['log'], initiator = LOCAL if self.constraints.is_initiator else REMOTE, initial_feerate=initial_feerate)
803+
self.hm = HTLCManager(log=state['log'], initiator = LOCAL if self.constraints.is_initiator else REMOTE, initial_feerate=initial_feerate, lock=self.db_lock)
803804
self.unfulfilled_htlcs = state["unfulfilled_htlcs"] # type: Dict[int, Optional[str]]
804805
# ^ htlc_id -> onion_packet_hex
805806
self._state = ChannelState[state['state']]

electrum/lnhtlc.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from copy import deepcopy
22
from typing import Sequence, Tuple, Dict, TYPE_CHECKING, Set
3+
import threading
34

45
from .lnutil import SENT, RECEIVED, LOCAL, REMOTE, HTLCOwner, UpdateAddHtlc, Direction, FeeUpdate
56
from .util import bfh, with_lock
@@ -21,7 +22,7 @@
2122

2223
class HTLCManager:
2324

24-
def __init__(self, log: 'StoredDict', *, initiator=None, initial_feerate=None):
25+
def __init__(self, log: 'StoredDict', *, initiator=None, initial_feerate=None, lock=None):
2526

2627
if len(log) == 0:
2728
# note: "htlc_id" keys in dict are str! but due to json_db magic they can *almost* be treated as int...
@@ -41,7 +42,7 @@ def __init__(self, log: 'StoredDict', *, initiator=None, initial_feerate=None):
4142
# lnchannel sometimes calls us with Channel.db_lock (== log.lock) already taken,
4243
# and we ourselves often take log.lock (via StoredDict.__getitem__).
4344
# Hence, to avoid deadlocks, we reuse this same lock.
44-
self.lock = log.lock
45+
self.lock = lock if lock else threading.RLock()
4546

4647
self._init_maybe_active_htlc_ids()
4748

electrum/lnpeer.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
from .lntransport import LNTransport, LNTransportBase, LightningPeerConnectionClosed, HandshakeFailed
5353
from .lnmsg import encode_msg, decode_msg, UnknownOptionalMsgType, FailedToParseMsg
5454
from .interface import GracefulDisconnect
55-
from .json_db import StoredDict
5655
from .invoices import PR_PAID
5756
from .fee_policy import FEE_LN_ETA_TARGET, FEERATE_PER_KW_MIN_RELAY_LIGHTNING
5857
from .channel_db import FLAG_DIRECTION
@@ -1211,10 +1210,10 @@ async def channel_establishment_flow(
12111210
self.send_warning(channel_id, message=str(e), close_connection=True)
12121211
chan.open_with_first_pcp(remote_per_commitment_point, remote_sig)
12131212
chan.set_state(ChannelState.OPENING)
1213+
chan = self.lnworker.add_new_channel(chan)
12141214
if zeroconf:
12151215
chan.set_state(ChannelState.FUNDED)
12161216
self.send_channel_ready(chan)
1217-
self.lnworker.add_new_channel(chan)
12181217
return chan, funding_tx
12191218

12201219
def create_channel_storage(self, channel_id, outpoint, local_config, remote_config, constraints, channel_type):
@@ -1235,7 +1234,7 @@ def create_channel_storage(self, channel_id, outpoint, local_config, remote_conf
12351234
"revocation_store": {},
12361235
"channel_type": channel_type,
12371236
}
1238-
return StoredDict(chan_dict, self.lnworker.db)
1237+
return chan_dict
12391238

12401239
@non_blocking_msg_handler
12411240
async def on_open_channel(self, payload):
@@ -1431,13 +1430,13 @@ async def on_open_channel(self, payload):
14311430
self.funding_signed_sent.add(chan.channel_id)
14321431
chan.open_with_first_pcp(payload['first_per_commitment_point'], remote_sig)
14331432
chan.set_state(ChannelState.OPENING)
1433+
chan = self.lnworker.add_new_channel(chan)
14341434
if is_zeroconf:
14351435
# FIXME shouldn't we wait until funding_tx is at least in the mempool?!
14361436
# We haven't even validated funding_tx really contains the multisig funding output!
14371437
# This is unsafe. MUST be reworked before mainnet usage.
14381438
chan.set_state(ChannelState.FUNDED)
14391439
self.send_channel_ready(chan)
1440-
self.lnworker.add_new_channel(chan)
14411440

14421441
def _cleanup_temp_channelids(self) -> None:
14431442
self.temp_id_to_id = {

electrum/lnworker.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1662,16 +1662,31 @@ def add_channel(self, chan: Channel):
16621662
self.lnwatcher.add_channel(chan)
16631663

16641664
def add_new_channel(self, chan: Channel):
1665-
self.add_channel(chan)
1665+
# delete the old channel object, becauses it uses a dict
1666+
assert type(chan.storage) is dict
1667+
channel_id = chan.channel_id.hex()
16661668
channels_db = self.db.get_dict('channels')
1667-
channels_db[chan.channel_id.hex()] = chan.storage
1669+
channels_db[channel_id] = chan.storage
1670+
jit_opening_fee = chan.jit_opening_fee
1671+
peer_state = chan.peer_state
1672+
del chan
1673+
storage = channels_db[channel_id] # StoredDict
1674+
chan = Channel(
1675+
storage,
1676+
lnworker=self,
1677+
jit_opening_fee=jit_opening_fee,
1678+
)
1679+
chan.peer_state = peer_state
1680+
self.add_channel(chan)
16681681
self.wallet.set_reserved_addresses_for_chan(chan, reserved=True)
16691682
try:
16701683
self.save_channel(chan)
16711684
except Exception:
16721685
chan.set_state(ChannelState.REDEEMED)
16731686
self.remove_channel(chan.channel_id)
16741687
raise
1688+
# return new channel object
1689+
return chan
16751690

16761691
def make_local_config_for_new_channel(
16771692
self,

tests/lnhelpers.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
from electrum.channel_db import ChannelDB
2323
from electrum.lnworker import LNWallet, PaySession
2424
from electrum.simple_config import SimpleConfig
25-
from electrum.stored_dict import StoredDict
2625
from electrum.fee_policy import FeeTimeEstimates, FEE_ETA_TARGETS
2726
from electrum.wallet import Standard_Wallet
2827

@@ -392,7 +391,7 @@ def _create_channel_state(
392391
'revocation_store': {},
393392
'channel_type': channel_type,
394393
}
395-
return StoredDict(state, None)
394+
return state
396395

397396

398397
def create_test_channels(

0 commit comments

Comments
 (0)