Browse Source

support option_static_remotekey

hard-fail-on-bad-server-string
ThomasV 5 years ago
parent
commit
2255b07157
  1. 9
      electrum/lnchannel.py
  2. 24
      electrum/lnpeer.py
  3. 41
      electrum/lnsweep.py
  4. 2
      electrum/lnutil.py
  5. 1
      electrum/lnworker.py

9
electrum/lnchannel.py

@ -230,6 +230,9 @@ class Channel(Logger):
self._chan_ann_without_sigs = chan_ann
return chan_ann
def is_static_remotekey_enabled(self):
return self.storage.get('static_remotekey_enabled')
def set_short_channel_id(self, short_id):
self.short_channel_id = short_id
self.storage["short_channel_id"] = short_id
@ -766,7 +769,11 @@ class Channel(Logger):
feerate,
self.constraints.is_initiator == (subject == LOCAL),
)
payment_pubkey = derive_pubkey(other_config.payment_basepoint.pubkey, this_point)
if self.is_static_remotekey_enabled():
payment_pubkey = other_config.payment_basepoint.pubkey
else:
payment_pubkey = derive_pubkey(other_config.payment_basepoint.pubkey, this_point)
return make_commitment(
ctn,
this_config.multisig_key.pubkey,

24
electrum/lnpeer.py

@ -119,7 +119,7 @@ class Peer(Logger):
async def initialize(self):
if isinstance(self.transport, LNTransport):
await self.transport.handshake()
self.send_message("init", gflen=0, lflen=1, localfeatures=self.localfeatures)
self.send_message("init", gflen=0, lflen=2, localfeatures=self.localfeatures)
self._sent_init = True
@property
@ -461,6 +461,9 @@ class Peer(Logger):
pass
self.lnworker.peer_closed(self)
def is_static_remotekey(self):
return bool(self.localfeatures & LnLocalFeatures.OPTION_STATIC_REMOTEKEY_OPT)
def make_local_config(self, funding_sat: int, push_msat: int, initiator: HTLCOwner) -> LocalConfig:
# key derivation
channel_counter = self.lnworker.get_and_inc_counter_for_channel_keys()
@ -469,8 +472,16 @@ class Peer(Logger):
initial_msat = funding_sat * 1000 - push_msat
else:
initial_msat = push_msat
if self.is_static_remotekey():
addr = self.lnworker.wallet.get_unused_address()
static_key = self.lnworker.wallet.get_public_key(addr) # just a pubkey
payment_basepoint = OnlyPubkeyKeypair(bfh(static_key))
else:
payment_basepoint = keypair_generator(LnKeyFamily.PAYMENT_BASE)
local_config=LocalConfig(
payment_basepoint=keypair_generator(LnKeyFamily.PAYMENT_BASE),
payment_basepoint=payment_basepoint,
multisig_key=keypair_generator(LnKeyFamily.MULTISIG),
htlc_basepoint=keypair_generator(LnKeyFamily.HTLC_BASE),
delayed_basepoint=keypair_generator(LnKeyFamily.DELAY_BASE),
@ -615,6 +626,7 @@ class Peer(Logger):
'data_loss_protect_remote_pcp': {},
"log": {},
"revocation_store": {},
"static_remotekey_enabled": self.is_static_remotekey(), # stored because it cannot be "downgraded", per BOLT2
}
channel_id = chan_dict.get('channel_id')
channels = self.lnworker.db.get_dict('channels')
@ -729,12 +741,16 @@ class Peer(Logger):
next_remote_ctn = chan.get_next_ctn(REMOTE)
assert self.localfeatures & LnLocalFeatures.OPTION_DATA_LOSS_PROTECT_OPT
# send message
srk_enabled = chan.is_static_remotekey_enabled()
if srk_enabled:
latest_secret, latest_point = chan.get_secret_and_point(LOCAL, 0)
else:
latest_secret, latest_point = chan.get_secret_and_point(LOCAL, latest_local_ctn)
if oldest_unrevoked_remote_ctn == 0:
last_rev_secret = 0
else:
last_rev_index = oldest_unrevoked_remote_ctn - 1
last_rev_secret = chan.revocation_store.retrieve_secret(RevocationStore.START_INDEX - last_rev_index)
latest_secret, latest_point = chan.get_secret_and_point(LOCAL, latest_local_ctn)
self.send_message(
"channel_reestablish",
channel_id=chan_id,
@ -824,6 +840,8 @@ class Peer(Logger):
if our_pcs != their_claim_of_our_last_per_commitment_secret:
self.logger.error(f"channel_reestablish: (DLP) local PCS mismatch: {bh2u(our_pcs)} != {bh2u(their_claim_of_our_last_per_commitment_secret)}")
return False
if chan.is_static_remotekey_enabled():
return True
try:
__, our_remote_pcp = chan.get_secret_and_point(REMOTE, their_next_local_ctn - 1)
except RemoteCtnTooFarInFuture:

41
electrum/lnsweep.py

@ -324,7 +324,9 @@ def create_sweeptxs_for_their_ctx(*, chan: 'Channel', ctx: Transaction,
witness_script = bh2u(make_commitment_output_to_local_witness_script(
our_revocation_pubkey, our_conf.to_self_delay, their_delayed_pubkey))
to_local_address = redeem_script_to_address('p2wsh', witness_script)
our_payment_pubkey = derive_pubkey(our_conf.payment_basepoint.pubkey, their_pcp)
# to remote address
bpk = our_conf.payment_basepoint.pubkey
our_payment_pubkey = bpk if chan.is_static_remotekey_enabled() else derive_pubkey(bpk, their_pcp)
to_remote_address = make_commitment_output_to_remote_address(our_payment_pubkey)
# test if this is their ctx
_logger.debug(f'testing their ctx: {to_local_address} {to_remote_address}')
@ -345,26 +347,27 @@ def create_sweeptxs_for_their_ctx(*, chan: 'Channel', ctx: Transaction,
our_htlc_privkey = derive_privkey(secret=int.from_bytes(our_conf.htlc_basepoint.privkey, 'big'), per_commitment_point=their_pcp)
our_htlc_privkey = ecc.ECPrivkey.from_secret_scalar(our_htlc_privkey)
their_htlc_pubkey = derive_pubkey(their_conf.htlc_basepoint.pubkey, their_pcp)
our_payment_bp_privkey = ecc.ECPrivkey(our_conf.payment_basepoint.privkey)
our_payment_privkey = derive_privkey(our_payment_bp_privkey.secret_scalar, their_pcp)
our_payment_privkey = ecc.ECPrivkey.from_secret_scalar(our_payment_privkey)
assert our_payment_pubkey == our_payment_privkey.get_public_key_bytes(compressed=True)
# to_local is handled by lnwatcher
# to_remote
output_idxs = ctx.get_output_idxs_from_address(to_remote_address)
if output_idxs:
output_idx = output_idxs.pop()
prevout = ctx.txid() + ':%d'%output_idx
sweep_tx = lambda: create_sweeptx_their_ctx_to_remote(
sweep_address=sweep_address,
ctx=ctx,
output_idx=output_idx,
our_payment_privkey=our_payment_privkey,
config=chan.lnworker.config)
txs[prevout] = SweepInfo(name='their_ctx_to_remote',
csv_delay=0,
cltv_expiry=0,
gen_tx=sweep_tx)
if not chan.is_static_remotekey_enabled():
our_payment_bp_privkey = ecc.ECPrivkey(our_conf.payment_basepoint.privkey)
our_payment_privkey = derive_privkey(our_payment_bp_privkey.secret_scalar, their_pcp)
our_payment_privkey = ecc.ECPrivkey.from_secret_scalar(our_payment_privkey)
assert our_payment_pubkey == our_payment_privkey.get_public_key_bytes(compressed=True)
output_idxs = ctx.get_output_idxs_from_address(to_remote_address)
if output_idxs:
output_idx = output_idxs.pop()
prevout = ctx.txid() + ':%d'%output_idx
sweep_tx = lambda: create_sweeptx_their_ctx_to_remote(
sweep_address=sweep_address,
ctx=ctx,
output_idx=output_idx,
our_payment_privkey=our_payment_privkey,
config=chan.lnworker.config)
txs[prevout] = SweepInfo(name='their_ctx_to_remote',
csv_delay=0,
cltv_expiry=0,
gen_tx=sweep_tx)
# HTLCs
def create_sweeptx_for_htlc(htlc: 'UpdateAddHtlc', is_received_htlc: bool,
ctx_output_idx: int) -> None:

2
electrum/lnutil.py

@ -630,6 +630,8 @@ class LnLocalFeatures(IntFlag):
OPTION_UPFRONT_SHUTDOWN_SCRIPT_OPT = 1 << 5
GOSSIP_QUERIES_REQ = 1 << 6
GOSSIP_QUERIES_OPT = 1 << 7
OPTION_STATIC_REMOTEKEY_REQ = 1 << 12
OPTION_STATIC_REMOTEKEY_OPT = 1 << 13
# note that these are powers of two, not the bits themselves
LN_LOCAL_FEATURES_KNOWN_SET = set(LnLocalFeatures)

1
electrum/lnworker.py

@ -130,6 +130,7 @@ class LNWorker(Logger):
# note that e.g. DATA_LOSS_PROTECT is needed for LNGossip as many peers require it
self.localfeatures = LnLocalFeatures(0)
self.localfeatures |= LnLocalFeatures.OPTION_DATA_LOSS_PROTECT_OPT
self.localfeatures |= LnLocalFeatures.OPTION_STATIC_REMOTEKEY_OPT
def channels_for_peer(self, node_id):
return {}

Loading…
Cancel
Save