Browse Source

network: randomise the order of address subscriptions

Before this, we were subscribing to our addresses in their bip32 order,
leaking this information to servers. While this leak seems mostly harmless,
it is trivial to fix.
bip39-recovery
SomberNight 5 years ago
parent
commit
2c962abe51
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. 6
      electrum/lnwatcher.py
  2. 6
      electrum/lnworker.py
  3. 4
      electrum/synchronizer.py
  4. 11
      electrum/util.py

6
electrum/lnwatcher.py

@ -11,7 +11,7 @@ from typing import NamedTuple, Dict
from . import util
from .sql_db import SqlDB, sql
from .wallet_db import WalletDB
from .util import bh2u, bfh, log_exceptions, ignore_exceptions, TxMinedInfo
from .util import bh2u, bfh, log_exceptions, ignore_exceptions, TxMinedInfo, random_shuffled_copy
from .address_synchronizer import AddressSynchronizer, TX_HEIGHT_LOCAL, TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED
from .transaction import Transaction, TxOutpoint
@ -278,8 +278,8 @@ class WatchTower(LNWatcher):
async def start_watching(self):
# I need to watch the addresses from sweepstore
l = await self.sweepstore.list_channels()
for outpoint, address in l:
lst = await self.sweepstore.list_channels()
for outpoint, address in random_shuffled_copy(lst):
self.add_channel(outpoint, address)
async def do_breach_remedy(self, funding_outpoint, closing_tx, spenders):

6
electrum/lnworker.py

@ -35,7 +35,7 @@ from .crypto import sha256
from .bip32 import BIP32Node
from .util import bh2u, bfh, InvoiceError, resolve_dns_srv, is_ip_address, log_exceptions
from .util import ignore_exceptions, make_aiohttp_session, SilentTaskGroup
from .util import timestamp_to_datetime
from .util import timestamp_to_datetime, random_shuffled_copy
from .util import MyEncoder
from .logging import Logger
from .lntransport import LNTransport, LNResponderTransport
@ -499,7 +499,7 @@ class LNWallet(LNWorker):
# note: accessing channels (besides simple lookup) needs self.lock!
self._channels = {} # type: Dict[bytes, Channel]
channels = self.db.get_dict("channels")
for channel_id, c in channels.items():
for channel_id, c in random_shuffled_copy(channels.items()):
self._channels[bfh(channel_id)] = Channel(c, sweep_address=self.sweep_address, lnworker=self)
self.pending_payments = defaultdict(asyncio.Future) # type: Dict[bytes, asyncio.Future[BarePaymentAttemptLog]]
@ -1397,7 +1397,7 @@ class LNBackups(Logger):
self.wallet = wallet
self.db = wallet.db
self.channel_backups = {}
for channel_id, cb in self.db.get_dict("channel_backups").items():
for channel_id, cb in random_shuffled_copy(self.db.get_dict("channel_backups").items()):
self.channel_backups[bfh(channel_id)] = ChannelBackup(cb, sweep_address=self.sweep_address, lnworker=self)
@property

4
electrum/synchronizer.py

@ -32,7 +32,7 @@ from aiorpcx import TaskGroup, run_in_thread, RPCError
from . import util
from .transaction import Transaction, PartialTransaction
from .util import bh2u, make_aiohttp_session, NetworkJobOnDefaultServer
from .util import bh2u, make_aiohttp_session, NetworkJobOnDefaultServer, random_shuffled_copy
from .bitcoin import address_to_scripthash, is_address
from .network import UntrustedServerReturnedError
from .logging import Logger
@ -240,7 +240,7 @@ class Synchronizer(SynchronizerBase):
if history == ['*']: continue
await self._request_missing_txs(history, allow_server_not_finding_tx=True)
# add addresses to bootstrap
for addr in self.wallet.get_addresses():
for addr in random_shuffled_copy(self.wallet.get_addresses()):
await self._add_address(addr)
# main loop
while True:

11
electrum/util.py

@ -24,7 +24,7 @@ import binascii
import os, sys, re, json
from collections import defaultdict, OrderedDict
from typing import (NamedTuple, Union, TYPE_CHECKING, Tuple, Optional, Callable, Any,
Sequence, Dict, Generic, TypeVar)
Sequence, Dict, Generic, TypeVar, List, Iterable)
from datetime import datetime
import decimal
from decimal import Decimal
@ -1398,3 +1398,12 @@ class JsonRPCClient:
async def coro(*args):
return await self.request(endpoint, *args)
setattr(self, endpoint, coro)
T = TypeVar('T')
def random_shuffled_copy(x: Iterable[T]) -> List[T]:
"""Returns a shuffled copy of the input."""
x_copy = list(x) # copy
random.shuffle(x_copy) # shuffle in-place
return x_copy

Loading…
Cancel
Save