Merge pull request #10031 from SomberNight/202507_walletdb_add_configvar_partial_writes_4
wallet_db: add configvar for partial_writes, disable by default
This commit is contained in:
@@ -507,7 +507,7 @@ class Daemon(Logger):
|
||||
config: SimpleConfig,
|
||||
) -> Optional[Abstract_Wallet]:
|
||||
path = standardize_path(path)
|
||||
storage = WalletStorage(path)
|
||||
storage = WalletStorage(path, allow_partial_writes=config.WALLET_PARTIAL_WRITES)
|
||||
if not storage.file_exists():
|
||||
raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), path)
|
||||
if storage.is_encrypted():
|
||||
|
||||
@@ -421,11 +421,7 @@ class JsonDB(Logger):
|
||||
|
||||
@locked
|
||||
def write(self):
|
||||
if (
|
||||
not self.storage.file_exists()
|
||||
or self.storage.is_encrypted()
|
||||
or self.storage.needs_consolidation()
|
||||
):
|
||||
if self.storage.should_do_full_write_next():
|
||||
self.write_and_force_consolidation()
|
||||
else:
|
||||
self._append_pending_changes()
|
||||
|
||||
@@ -687,6 +687,11 @@ class SimpleConfig(Logger):
|
||||
This can eliminate a serious privacy issue where a malicious user can track your spends by sending small payments
|
||||
to a previously-paid address of yours that would then be included with unrelated inputs in your future payments."""),
|
||||
)
|
||||
WALLET_PARTIAL_WRITES = ConfigVar(
|
||||
'wallet_partial_writes', default=False, type_=bool,
|
||||
long_desc=lambda: _("""Allows partial updates to be written to disk for the wallet DB.
|
||||
If disabled, the full wallet file is written to disk for every change. Experimental."""),
|
||||
)
|
||||
|
||||
FX_USE_EXCHANGE_RATE = ConfigVar('use_exchange_rate', default=False, type_=bool)
|
||||
FX_CURRENCY = ConfigVar('currency', default='EUR', type_=str)
|
||||
|
||||
@@ -64,11 +64,17 @@ class WalletStorage(Logger):
|
||||
|
||||
# TODO maybe split this into separate create() and open() classmethods, to prevent some bugs.
|
||||
# Until then, the onus is on the caller to check file_exists().
|
||||
def __init__(self, path):
|
||||
def __init__(
|
||||
self,
|
||||
path,
|
||||
*,
|
||||
allow_partial_writes: bool = False,
|
||||
):
|
||||
Logger.__init__(self)
|
||||
self.path = standardize_path(path)
|
||||
self._file_exists = bool(self.path and os.path.exists(self.path))
|
||||
self.logger.info(f"wallet path {self.path}")
|
||||
self._allow_partial_writes = allow_partial_writes
|
||||
self.pubkey = None
|
||||
self.decrypted = ''
|
||||
try:
|
||||
@@ -112,6 +118,7 @@ class WalletStorage(Logger):
|
||||
|
||||
def append(self, data: str) -> None:
|
||||
""" append data to file. for the moment, only non-encrypted file"""
|
||||
assert self._allow_partial_writes
|
||||
assert not self.is_encrypted()
|
||||
with open(self.path, "rb+") as f:
|
||||
pos = f.seek(0, os.SEEK_END)
|
||||
@@ -122,9 +129,18 @@ class WalletStorage(Logger):
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
|
||||
def needs_consolidation(self):
|
||||
def _needs_consolidation(self):
|
||||
return self.pos > 2 * self.init_pos
|
||||
|
||||
def should_do_full_write_next(self) -> bool:
|
||||
"""If false, next action can be a partial-write ('append')."""
|
||||
return (
|
||||
not self.file_exists()
|
||||
or self.is_encrypted()
|
||||
or self._needs_consolidation()
|
||||
or not self._allow_partial_writes
|
||||
)
|
||||
|
||||
def file_exists(self) -> bool:
|
||||
return self._file_exists
|
||||
|
||||
|
||||
@@ -4189,7 +4189,7 @@ def create_new_wallet(
|
||||
gap_limit: Optional[int] = None
|
||||
) -> dict:
|
||||
"""Create a new wallet"""
|
||||
storage = WalletStorage(path)
|
||||
storage = WalletStorage(path, allow_partial_writes=config.WALLET_PARTIAL_WRITES)
|
||||
if storage.file_exists():
|
||||
raise UserFacingException("Remove the existing wallet first!")
|
||||
db = WalletDB('', storage=storage, upgrade=True)
|
||||
@@ -4226,7 +4226,7 @@ def restore_wallet_from_text(
|
||||
if path is None: # create wallet in-memory
|
||||
storage = None
|
||||
else:
|
||||
storage = WalletStorage(path)
|
||||
storage = WalletStorage(path, allow_partial_writes=config.WALLET_PARTIAL_WRITES)
|
||||
if storage.file_exists():
|
||||
raise UserFacingException("Remove the existing wallet first!")
|
||||
if encrypt_file is None:
|
||||
|
||||
@@ -1289,7 +1289,13 @@ class WalletDB(JsonDB):
|
||||
storage: Optional['WalletStorage'] = None,
|
||||
upgrade: bool = False,
|
||||
):
|
||||
JsonDB.__init__(self, s, storage=storage, encoder=MyEncoder, upgrader=partial(upgrade_wallet_db, do_upgrade=upgrade))
|
||||
JsonDB.__init__(
|
||||
self,
|
||||
s,
|
||||
storage=storage,
|
||||
encoder=MyEncoder,
|
||||
upgrader=partial(upgrade_wallet_db, do_upgrade=upgrade),
|
||||
)
|
||||
# create pointers
|
||||
self.load_transactions()
|
||||
# load plugins that are conditional on wallet type
|
||||
|
||||
Reference in New Issue
Block a user