Browse Source

walletdb: change structure of prevouts_by_scripthash, and db upgrade

this fixes the test case added in prev
master
SomberNight 2 years ago
parent
commit
79aba5364c
No known key found for this signature in database
GPG Key ID: B33B5F232C6271E9
  1. 37
      electrum/wallet_db.py

37
electrum/wallet_db.py

@ -69,7 +69,7 @@ class WalletUnfinished(WalletFileException):
# seed_version is now used for the version of the wallet file
OLD_SEED_VERSION = 4 # electrum versions < 2.0
NEW_SEED_VERSION = 11 # electrum versions >= 2.0
FINAL_SEED_VERSION = 57 # electrum >= 2.7 will set this to prevent
FINAL_SEED_VERSION = 58 # electrum >= 2.7 will set this to prevent
# old versions from overwriting new format
@ -103,7 +103,6 @@ class WalletFileExceptionVersion51(WalletFileException): pass
# register dicts that require value conversions not handled by constructor
json_db.register_dict('transactions', lambda x: tx_from_any(x, deserialize=False), None)
json_db.register_dict('prevouts_by_scripthash', lambda x: set(tuple(k) for k in x), None)
json_db.register_dict('data_loss_protect_remote_pcp', lambda x: bytes.fromhex(x), None)
json_db.register_dict('contacts', tuple, None)
# register dicts that require key conversion
@ -230,6 +229,7 @@ class WalletDBUpgrader(Logger):
self._convert_version_55()
self._convert_version_56()
self._convert_version_57()
self._convert_version_58()
self.put('seed_version', FINAL_SEED_VERSION) # just to be sure
def _convert_wallet_type(self):
@ -1107,6 +1107,25 @@ class WalletDBUpgrader(Logger):
self.data.pop('seed_type', None)
self.data['seed_version'] = 57
def _convert_version_58(self):
# re-construct prevouts_by_scripthash
# new structure: scripthash -> outpoint -> value
if not self._is_upgrade_method_needed(57, 57):
return
from .bitcoin import script_to_scripthash
transactions = self.get('transactions', {}) # txid -> raw_tx
prevouts_by_scripthash = {}
for txid, raw_tx in transactions.items():
tx = Transaction(raw_tx)
for idx, txout in enumerate(tx.outputs()):
outpoint = f"{txid}:{idx}"
scripthash = script_to_scripthash(txout.scriptpubkey.hex())
if scripthash not in prevouts_by_scripthash:
prevouts_by_scripthash[scripthash] = {}
prevouts_by_scripthash[scripthash][outpoint] = txout.value
self.put('prevouts_by_scripthash', prevouts_by_scripthash)
self.data['seed_version'] = 58
def _convert_imported(self):
if not self._is_upgrade_method_needed(0, 13):
return
@ -1362,23 +1381,23 @@ class WalletDB(JsonDB):
assert isinstance(prevout, TxOutpoint)
assert isinstance(value, int)
if scripthash not in self._prevouts_by_scripthash:
self._prevouts_by_scripthash[scripthash] = set()
self._prevouts_by_scripthash[scripthash].add((prevout.to_str(), value))
self._prevouts_by_scripthash[scripthash] = dict()
self._prevouts_by_scripthash[scripthash][prevout.to_str()] = value
@modifier
def remove_prevout_by_scripthash(self, scripthash: str, *, prevout: TxOutpoint, value: int) -> None:
assert isinstance(scripthash, str)
assert isinstance(prevout, TxOutpoint)
assert isinstance(value, int)
self._prevouts_by_scripthash[scripthash].discard((prevout.to_str(), value))
self._prevouts_by_scripthash[scripthash].pop(prevout.to_str(), None)
if not self._prevouts_by_scripthash[scripthash]:
self._prevouts_by_scripthash.pop(scripthash)
@locked
def get_prevouts_by_scripthash(self, scripthash: str) -> Set[Tuple[TxOutpoint, int]]:
assert isinstance(scripthash, str)
prevouts_and_values = self._prevouts_by_scripthash.get(scripthash, set())
return {(TxOutpoint.from_str(prevout), value) for prevout, value in prevouts_and_values}
prevouts_and_values = self._prevouts_by_scripthash.get(scripthash, {})
return {(TxOutpoint.from_str(prevout), value) for prevout, value in prevouts_and_values.items()}
@modifier
def add_transaction(self, tx_hash: str, tx: Transaction) -> None:
@ -1615,8 +1634,8 @@ class WalletDB(JsonDB):
self.history = self.get_dict('addr_history') # address -> list of (txid, height)
self.verified_tx = self.get_dict('verified_tx3') # txid -> (height, timestamp, txpos, header_hash)
self.tx_fees = self.get_dict('tx_fees') # type: Dict[str, TxFeesValue]
# scripthash -> set of (outpoint, value)
self._prevouts_by_scripthash = self.get_dict('prevouts_by_scripthash') # type: Dict[str, Set[Tuple[str, int]]]
# scripthash -> outpoint -> value
self._prevouts_by_scripthash = self.get_dict('prevouts_by_scripthash') # type: Dict[str, Dict[str, int]]
# remove unreferenced tx
for tx_hash in list(self.transactions.keys()):
if not self.get_txi_addresses(tx_hash) and not self.get_txo_addresses(tx_hash):

Loading…
Cancel
Save