tests: lnpeer: fix cyclic lnworker.wallet.lnworker inconsistency
These better hold, lol: wallet.lnworker.wallet == wallet lnworker.wallet.lnworker == lnworker
This commit is contained in:
@@ -4262,7 +4262,7 @@ class Wallet(object):
|
|||||||
|
|
||||||
def __new__(cls, db: 'WalletDB', *, config: SimpleConfig) -> Abstract_Wallet:
|
def __new__(cls, db: 'WalletDB', *, config: SimpleConfig) -> Abstract_Wallet:
|
||||||
wallet_type = db.get('wallet_type')
|
wallet_type = db.get('wallet_type')
|
||||||
WalletClass = Wallet.wallet_class(wallet_type)
|
WalletClass = cls.wallet_class(wallet_type)
|
||||||
wallet = WalletClass(db, config=config)
|
wallet = WalletClass(db, config=config)
|
||||||
return wallet
|
return wallet
|
||||||
|
|
||||||
@@ -4320,6 +4320,7 @@ def restore_wallet_from_text(
|
|||||||
encrypt_file: Optional[bool] = None,
|
encrypt_file: Optional[bool] = None,
|
||||||
gap_limit: Optional[int] = None,
|
gap_limit: Optional[int] = None,
|
||||||
gap_limit_for_change: Optional[int] = None,
|
gap_limit_for_change: Optional[int] = None,
|
||||||
|
wallet_factory = Wallet, # used in tests
|
||||||
) -> dict:
|
) -> dict:
|
||||||
"""Restore a wallet from text. Text can be a seed phrase, a master
|
"""Restore a wallet from text. Text can be a seed phrase, a master
|
||||||
public key, a master private key, a list of bitcoin addresses
|
public key, a master private key, a list of bitcoin addresses
|
||||||
@@ -4365,7 +4366,7 @@ def restore_wallet_from_text(
|
|||||||
db.put('gap_limit', gap_limit)
|
db.put('gap_limit', gap_limit)
|
||||||
if gap_limit_for_change is not None:
|
if gap_limit_for_change is not None:
|
||||||
db.put('gap_limit_for_change', gap_limit_for_change)
|
db.put('gap_limit_for_change', gap_limit_for_change)
|
||||||
wallet = Wallet(db, config=config)
|
wallet = wallet_factory(db, config=config)
|
||||||
if db.storage:
|
if db.storage:
|
||||||
assert not db.storage.file_exists(), "file was created too soon! plaintext keys might have been written to disk"
|
assert not db.storage.file_exists(), "file was created too soon! plaintext keys might have been written to disk"
|
||||||
wallet.update_password(old_pw=None, new_pw=password, encrypt_storage=encrypt_file)
|
wallet.update_password(old_pw=None, new_pw=password, encrypt_storage=encrypt_file)
|
||||||
|
|||||||
@@ -175,12 +175,12 @@ def create_test_channels(
|
|||||||
remote_max_inflight = funding_sat * 1000 if remote_max_inflight is None else remote_max_inflight
|
remote_max_inflight = funding_sat * 1000 if remote_max_inflight is None else remote_max_inflight
|
||||||
alice_raw = [bip32("m/" + str(i)) for i in range(5)]
|
alice_raw = [bip32("m/" + str(i)) for i in range(5)]
|
||||||
bob_raw = [bip32("m/" + str(i)) for i in range(5,11)]
|
bob_raw = [bip32("m/" + str(i)) for i in range(5,11)]
|
||||||
alice_privkeys = [lnutil.Keypair(privkey_to_pubkey(x), x) for x in alice_raw]
|
alice_privkeys = [lnutil.Keypair(privkey_to_pubkey(x), x) for x in alice_raw] # TODO make it depend on alice_lnwallet
|
||||||
bob_privkeys = [lnutil.Keypair(privkey_to_pubkey(x), x) for x in bob_raw]
|
bob_privkeys = [lnutil.Keypair(privkey_to_pubkey(x), x) for x in bob_raw]
|
||||||
alice_pubkeys = [lnutil.OnlyPubkeyKeypair(x.pubkey) for x in alice_privkeys]
|
alice_pubkeys = [lnutil.OnlyPubkeyKeypair(x.pubkey) for x in alice_privkeys]
|
||||||
bob_pubkeys = [lnutil.OnlyPubkeyKeypair(x.pubkey) for x in bob_privkeys]
|
bob_pubkeys = [lnutil.OnlyPubkeyKeypair(x.pubkey) for x in bob_privkeys]
|
||||||
|
|
||||||
alice_seed = random_gen.get_bytes(32)
|
alice_seed = random_gen.get_bytes(32) # TODO make it depend on alice_lnwallet
|
||||||
bob_seed = random_gen.get_bytes(32)
|
bob_seed = random_gen.get_bytes(32)
|
||||||
|
|
||||||
alice_first = lnutil.secret_to_pubkey(
|
alice_first = lnutil.secret_to_pubkey(
|
||||||
@@ -201,7 +201,9 @@ def create_test_channels(
|
|||||||
max_accepted_htlcs=max_accepted_htlcs,
|
max_accepted_htlcs=max_accepted_htlcs,
|
||||||
),
|
),
|
||||||
name=f"{alice_name}->{bob_name}",
|
name=f"{alice_name}->{bob_name}",
|
||||||
initial_feerate=feerate),
|
initial_feerate=feerate,
|
||||||
|
lnworker=alice_lnwallet,
|
||||||
|
),
|
||||||
lnchannel.Channel(
|
lnchannel.Channel(
|
||||||
create_channel_state(
|
create_channel_state(
|
||||||
funding_txid, funding_index, funding_sat, False, remote_amount,
|
funding_txid, funding_index, funding_sat, False, remote_amount,
|
||||||
@@ -212,7 +214,9 @@ def create_test_channels(
|
|||||||
max_accepted_htlcs=max_accepted_htlcs,
|
max_accepted_htlcs=max_accepted_htlcs,
|
||||||
),
|
),
|
||||||
name=f"{bob_name}->{alice_name}",
|
name=f"{bob_name}->{alice_name}",
|
||||||
initial_feerate=feerate)
|
initial_feerate=feerate,
|
||||||
|
lnworker=bob_lnwallet,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
alice.hm.log[LOCAL]['ctn'] = 0
|
alice.hm.log[LOCAL]['ctn'] = 0
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ from electrum.interface import GracefulDisconnect
|
|||||||
from electrum.simple_config import SimpleConfig
|
from electrum.simple_config import SimpleConfig
|
||||||
from electrum.fee_policy import FeeTimeEstimates, FEE_ETA_TARGETS
|
from electrum.fee_policy import FeeTimeEstimates, FEE_ETA_TARGETS
|
||||||
from electrum.mpp_split import split_amount_normal
|
from electrum.mpp_split import split_amount_normal
|
||||||
from electrum.wallet import Abstract_Wallet
|
from electrum.wallet import Abstract_Wallet, Standard_Wallet
|
||||||
|
|
||||||
from .test_lnchannel import create_test_channels
|
from .test_lnchannel import create_test_channels
|
||||||
from .test_bitcoin import needs_test_with_all_chacha20_implementations
|
from .test_bitcoin import needs_test_with_all_chacha20_implementations
|
||||||
@@ -116,93 +116,70 @@ class MockLNGossip:
|
|||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
|
|
||||||
class MockLNPeerManager(LNPeerManager):
|
class MockWalletFactory(electrum.wallet.Wallet):
|
||||||
def __init__(
|
|
||||||
self,
|
@staticmethod
|
||||||
*,
|
def wallet_class(wallet_type):
|
||||||
node_keypair,
|
real_wallet_class = electrum.wallet.Wallet.wallet_class(wallet_type)
|
||||||
config: SimpleConfig,
|
if real_wallet_class is Standard_Wallet:
|
||||||
features: LnFeatures,
|
return MockStandardWallet
|
||||||
lnwallet: LNWallet,
|
return real_wallet_class
|
||||||
network: 'MockNetwork',
|
|
||||||
):
|
|
||||||
LNPeerManager.__init__(
|
|
||||||
self,
|
|
||||||
node_keypair=node_keypair,
|
|
||||||
lnwallet_or_lngossip=lnwallet,
|
|
||||||
features=features,
|
|
||||||
config=config,
|
|
||||||
)
|
|
||||||
self.network = network
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache()
|
class MockStandardWallet(Standard_Wallet):
|
||||||
def _bip32_from_name(name: str) -> bip32.BIP32Node:
|
def _init_lnworker(self):
|
||||||
# note: unlike a serialized xprv, the bip32 node can be cached easily,
|
ln_xprv = self.db.get('lightning_xprv') or self.db.get('lightning_privkey2')
|
||||||
# as it does not depend on constant.net (testnet/mainnet) network bytes
|
assert ln_xprv
|
||||||
sequence = [ord(c) for c in name]
|
self.lnworker = MockLNWallet(self, ln_xprv)
|
||||||
bip32_node = bip32.BIP32Node.from_rootseed(b"9dk", xtype='standard').subkey_at_private_derivation(sequence)
|
|
||||||
return bip32_node
|
|
||||||
|
|
||||||
|
def basename(self):
|
||||||
|
passphrase = self.db.get("keystore").get("passphrase")
|
||||||
|
assert passphrase
|
||||||
|
return passphrase # lol, super secure name
|
||||||
|
|
||||||
|
def create_mock_lnwallet(*, name, has_anchors) -> 'MockLNWallet':
|
||||||
|
_user_dir = tempfile.mkdtemp(prefix="electrum-lnpeer-test-")
|
||||||
|
config = SimpleConfig({}, read_user_dir_function=lambda: _user_dir)
|
||||||
|
config.ENABLE_ANCHOR_CHANNELS = has_anchors
|
||||||
|
config.INITIAL_TRAMPOLINE_FEE_LEVEL = 0
|
||||||
|
|
||||||
|
network = MockNetwork(config=config)
|
||||||
|
|
||||||
|
wallet = restore_wallet_from_text__for_unittest(
|
||||||
|
"9dk", path=None, passphrase=name, config=config,
|
||||||
|
wallet_factory=MockWalletFactory,
|
||||||
|
)['wallet'] # type: MockStandardWallet
|
||||||
|
wallet.is_up_to_date = lambda: True
|
||||||
|
wallet.adb.network = wallet.network = network
|
||||||
|
|
||||||
|
lnworker = wallet.lnworker
|
||||||
|
assert isinstance(lnworker, MockLNWallet), f"{lnworker=!r}"
|
||||||
|
lnworker._user_dir = _user_dir
|
||||||
|
lnworker.lnpeermgr.network = network
|
||||||
|
lnworker.logger.info(f"created LNWallet[{name}] with nodeID={lnworker.node_keypair.pubkey.hex()}")
|
||||||
|
return lnworker
|
||||||
|
|
||||||
class MockLNWallet(LNWallet):
|
class MockLNWallet(LNWallet):
|
||||||
MPP_EXPIRY = 2 # HTLC timestamps are cast to int, so this cannot be 1
|
MPP_EXPIRY = 2 # HTLC timestamps are cast to int, so this cannot be 1
|
||||||
TIMEOUT_SHUTDOWN_FAIL_PENDING_HTLCS = 0
|
TIMEOUT_SHUTDOWN_FAIL_PENDING_HTLCS = 0
|
||||||
MPP_SPLIT_PART_FRACTION = 1 # this disables the forced splitting
|
MPP_SPLIT_PART_FRACTION = 1 # this disables the forced splitting
|
||||||
|
|
||||||
def __init__(self, *, name, has_anchors):
|
def __init__(self, *args, **kwargs):
|
||||||
self.name = name
|
LNWallet.__init__(self, *args, **kwargs)
|
||||||
|
self.features &= ~LnFeatures.BASIC_MPP_OPT # by default, disable MPP
|
||||||
self._user_dir = tempfile.mkdtemp(prefix="electrum-lnpeer-test-")
|
|
||||||
self.config = SimpleConfig({}, read_user_dir_function=lambda: self._user_dir)
|
|
||||||
self.config.ENABLE_ANCHOR_CHANNELS = has_anchors
|
|
||||||
self.config.INITIAL_TRAMPOLINE_FEE_LEVEL = 0
|
|
||||||
|
|
||||||
network = MockNetwork(config=self.config)
|
|
||||||
|
|
||||||
wallet = restore_wallet_from_text__for_unittest(
|
|
||||||
"9dk", path=None, passphrase=name, config=self.config)['wallet'] # type: Abstract_Wallet
|
|
||||||
wallet.is_up_to_date = lambda: True
|
|
||||||
wallet.adb.network = wallet.network = network
|
|
||||||
#assert wallet.lnworker is None # FIXME xxxxx wallet already has another lnworker by now >.<
|
|
||||||
|
|
||||||
features = LnFeatures(0)
|
|
||||||
features |= LnFeatures.OPTION_DATA_LOSS_PROTECT_OPT
|
|
||||||
features |= LnFeatures.OPTION_UPFRONT_SHUTDOWN_SCRIPT_OPT
|
|
||||||
features |= LnFeatures.VAR_ONION_OPT
|
|
||||||
features |= LnFeatures.PAYMENT_SECRET_OPT
|
|
||||||
features |= LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM
|
|
||||||
features |= LnFeatures.OPTION_CHANNEL_TYPE_OPT
|
|
||||||
features |= LnFeatures.OPTION_SCID_ALIAS_OPT
|
|
||||||
features |= LnFeatures.OPTION_STATIC_REMOTEKEY_OPT
|
|
||||||
|
|
||||||
ln_xprv = _bip32_from_name(name).to_xprv()
|
|
||||||
LNWallet.__init__(self, wallet=wallet, xprv=ln_xprv, features=features)
|
|
||||||
|
|
||||||
self.lnpeermgr = MockLNPeerManager(
|
|
||||||
node_keypair=self.node_keypair,
|
|
||||||
config=self.config,
|
|
||||||
features=features,
|
|
||||||
lnwallet=self,
|
|
||||||
network=network,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.logger.info(f"created LNWallet[{name}] with nodeID={self.node_keypair.pubkey.hex()}")
|
|
||||||
|
|
||||||
def _add_channel(self, chan: Channel):
|
def _add_channel(self, chan: Channel):
|
||||||
self._channels[chan.channel_id] = chan
|
self._channels[chan.channel_id] = chan
|
||||||
|
# assert chan.lnworker == self # this fails as some tests are reusing chans in a weird way
|
||||||
chan.lnworker = self
|
chan.lnworker = self
|
||||||
|
|
||||||
@LNWallet.features.setter
|
@LNWallet.features.setter
|
||||||
def features(self, value):
|
def features(self, value):
|
||||||
self.lnpeermgr.features = value
|
self.lnpeermgr.features = value
|
||||||
|
|
||||||
def save_channel(self, chan):
|
@property
|
||||||
pass
|
def name(self):
|
||||||
#print("Ignoring channel save")
|
return self.wallet.basename()
|
||||||
|
|
||||||
def diagnostic_name(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
async def stop(self):
|
async def stop(self):
|
||||||
await LNWallet.stop(self)
|
await LNWallet.stop(self)
|
||||||
@@ -524,7 +501,7 @@ class TestPeer(ElectrumTestCase):
|
|||||||
def prepare_lnwallets(self, graph_definition) -> Mapping[str, MockLNWallet]:
|
def prepare_lnwallets(self, graph_definition) -> Mapping[str, MockLNWallet]:
|
||||||
workers = {} # type: Dict[str, MockLNWallet]
|
workers = {} # type: Dict[str, MockLNWallet]
|
||||||
for a, definition in graph_definition.items():
|
for a, definition in graph_definition.items():
|
||||||
workers[a] = MockLNWallet(name=a, has_anchors=self.TEST_ANCHOR_CHANNELS)
|
workers[a] = create_mock_lnwallet(name=a, has_anchors=self.TEST_ANCHOR_CHANNELS)
|
||||||
self._lnworkers_created.extend(list(workers.values()))
|
self._lnworkers_created.extend(list(workers.values()))
|
||||||
return workers
|
return workers
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ from electrum.util import bfh, read_json_file, OldTaskGroup, get_asyncio_loop
|
|||||||
from electrum.logging import console_stderr_handler
|
from electrum.logging import console_stderr_handler
|
||||||
|
|
||||||
from . import ElectrumTestCase
|
from . import ElectrumTestCase
|
||||||
from .test_lnpeer import keypair, MockLNWallet
|
from .test_lnpeer import create_mock_lnwallet
|
||||||
|
|
||||||
|
|
||||||
TIME_STEP = 0.01 # run tests 100 x faster
|
TIME_STEP = 0.01 # run tests 100 x faster
|
||||||
OnionMessageManager.SLEEP_DELAY *= TIME_STEP
|
OnionMessageManager.SLEEP_DELAY *= TIME_STEP
|
||||||
@@ -352,7 +353,7 @@ class TestOnionMessageManager(ElectrumTestCase):
|
|||||||
|
|
||||||
async def test_request_and_reply(self):
|
async def test_request_and_reply(self):
|
||||||
n = MockNetwork()
|
n = MockNetwork()
|
||||||
lnw = MockLNWallet(name='test_request_and_reply', has_anchors=False)
|
lnw = create_mock_lnwallet(name='test_request_and_reply', has_anchors=False)
|
||||||
|
|
||||||
def slow(*args, **kwargs):
|
def slow(*args, **kwargs):
|
||||||
time.sleep(2*TIME_STEP)
|
time.sleep(2*TIME_STEP)
|
||||||
@@ -398,7 +399,7 @@ class TestOnionMessageManager(ElectrumTestCase):
|
|||||||
|
|
||||||
async def test_forward(self):
|
async def test_forward(self):
|
||||||
n = MockNetwork()
|
n = MockNetwork()
|
||||||
lnw = MockLNWallet(name='alice', has_anchors=False)
|
lnw = create_mock_lnwallet(name='alice', has_anchors=False)
|
||||||
lnw.node_keypair = self.alice
|
lnw.node_keypair = self.alice
|
||||||
|
|
||||||
self.was_sent = False
|
self.was_sent = False
|
||||||
@@ -435,7 +436,7 @@ class TestOnionMessageManager(ElectrumTestCase):
|
|||||||
|
|
||||||
async def test_receive_unsolicited(self):
|
async def test_receive_unsolicited(self):
|
||||||
n = MockNetwork()
|
n = MockNetwork()
|
||||||
lnw = MockLNWallet(name='dave', has_anchors=False)
|
lnw = create_mock_lnwallet(name='dave', has_anchors=False)
|
||||||
lnw.node_keypair = self.dave
|
lnw.node_keypair = self.dave
|
||||||
|
|
||||||
t = OnionMessageManager(lnw)
|
t = OnionMessageManager(lnw)
|
||||||
|
|||||||
Reference in New Issue
Block a user