lightning: change derivation of funding_pubkey

Ideally, given an on-chain backup, after the remote force-closes, we should be able to spend our anchor output,
to CPFP the remote commitment tx (assuming the channel used OPTION_ANCHORS).
To spend the anchor output, we need to be able to sign with the local funding_privkey.

Previously we derived the funding_key from the channel_seed (which comes from os.urandom).
Prior to anchors, there was no use case for signing with the funding_key given a channel backup.
Now with anchors, we should make its derivation deterministic somehow, in a way so that it can
be derived given just an on-chain backup.
- one way would be to put some more data into the existing OP_RETURN
  - uses block space
  - the OP_RETURNs can be disabled via "use_recoverable_channels"
  - only the initiator can use OP_RETURNs (so what if channel is in incoming dir?)
- instead, new scheme for our funding_key:
  - we derive the funding_privkey from the lnworker root secret (derived from our bip32 seed)
  - for outgoing channels:
    - lnworker_root_secret + remote_node_id + funding_tx_nlocktime
  - for incoming channels:
    - lnworker_root_secret + remote_node_id + remote_funding_pubkey
  - a check is added to avoid reusing the same key between channels:
      not letting to user open more than one channel with the same peer in a single block
  - only the first 16 bytes of the remote_node_id are used, as the onchain backup OP_RETURNs only contain that
- as the funding_privkey cannot be derived from the channel_seed anymore, it is included in the
imported channel backups, which in turn need a new version defined
  - a wallet db upgrade is used to update already stored imported cbs
  - alternatively we could keep the imported cbs as-is, so no new version, no new funding_privkey field, as it is clearly somewhat redundant given on-chain backups can reconstruct it
    - however adding the field seems easier
      - otherwise the existing code would try to derive the funding_privkey from the channel_seed
      - also note: atm there is no field in the imported backups to distinguish anchor channels vs static-remotekey channels
This commit is contained in:
SomberNight
2025-01-14 16:14:01 +00:00
parent 8f5b395ddc
commit cba073dfd1
10 changed files with 190 additions and 24 deletions
+11 -1
View File
@@ -72,7 +72,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 = 59 # electrum >= 2.7 will set this to prevent
FINAL_SEED_VERSION = 60 # electrum >= 2.7 will set this to prevent
# old versions from overwriting new format
@@ -234,6 +234,7 @@ class WalletDBUpgrader(Logger):
self._convert_version_57()
self._convert_version_58()
self._convert_version_59()
self._convert_version_60()
self.put('seed_version', FINAL_SEED_VERSION) # just to be sure
def _convert_wallet_type(self):
@@ -1146,6 +1147,15 @@ class WalletDBUpgrader(Logger):
self.data['channels'] = channels
self.data['seed_version'] = 59
def _convert_version_60(self):
if not self._is_upgrade_method_needed(59, 59):
return
cbs = self.data.get('imported_channel_backups', {})
for channel_id, cb in list(cbs.items()):
if 'multisig_funding_privkey' not in cb:
cb['multisig_funding_privkey'] = None
self.data['seed_version'] = 60
def _convert_imported(self):
if not self._is_upgrade_method_needed(0, 13):
return