mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-08-23 17:47:31 +00:00
lnbase: fix pay(), save htlc_id's, generate onion packet correctly
This commit is contained in:
parent
34da1349e0
commit
b81fb44952
2 changed files with 68 additions and 36 deletions
|
@ -275,8 +275,8 @@ ChannelConfig = namedtuple("ChannelConfig", [
|
||||||
"payment_basepoint", "multisig_key", "htlc_basepoint", "delayed_basepoint", "revocation_basepoint",
|
"payment_basepoint", "multisig_key", "htlc_basepoint", "delayed_basepoint", "revocation_basepoint",
|
||||||
"to_self_delay", "dust_limit_sat", "max_htlc_value_in_flight_msat", "max_accepted_htlcs"])
|
"to_self_delay", "dust_limit_sat", "max_htlc_value_in_flight_msat", "max_accepted_htlcs"])
|
||||||
OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"])
|
OnlyPubkeyKeypair = namedtuple("OnlyPubkeyKeypair", ["pubkey"])
|
||||||
RemoteState = namedtuple("RemoteState", ["ctn", "next_per_commitment_point", "amount_sat", "revocation_store", "last_per_commitment_point"])
|
RemoteState = namedtuple("RemoteState", ["ctn", "next_per_commitment_point", "amount_sat", "revocation_store", "last_per_commitment_point", "next_htlc_id"])
|
||||||
LocalState = namedtuple("LocalState", ["ctn", "per_commitment_secret_seed", "amount_sat"])
|
LocalState = namedtuple("LocalState", ["ctn", "per_commitment_secret_seed", "amount_sat", "next_htlc_id"])
|
||||||
ChannelConstraints = namedtuple("ChannelConstraints", ["feerate", "capacity", "is_initiator", "funding_txn_minimum_depth"])
|
ChannelConstraints = namedtuple("ChannelConstraints", ["feerate", "capacity", "is_initiator", "funding_txn_minimum_depth"])
|
||||||
OpenChannel = namedtuple("OpenChannel", ["channel_id", "short_channel_id", "funding_outpoint", "local_config", "remote_config", "remote_state", "local_state", "constraints"])
|
OpenChannel = namedtuple("OpenChannel", ["channel_id", "short_channel_id", "funding_outpoint", "local_config", "remote_config", "remote_state", "local_state", "constraints"])
|
||||||
|
|
||||||
|
@ -563,6 +563,11 @@ def sign_and_get_sig_string(tx, local_config, remote_config):
|
||||||
sig_64 = sigencode_string_canonize(r, s, SECP256k1.generator.order())
|
sig_64 = sigencode_string_canonize(r, s, SECP256k1.generator.order())
|
||||||
return sig_64
|
return sig_64
|
||||||
|
|
||||||
|
def is_synced(network):
|
||||||
|
local_height, server_height = network.get_status_value("updated")
|
||||||
|
synced = server_height != 0 and network.is_up_to_date() and local_height >= server_height
|
||||||
|
return synced
|
||||||
|
|
||||||
class Peer(PrintError):
|
class Peer(PrintError):
|
||||||
def __init__(self, host, port, pubkey, privkey, request_initial_sync=False, network=None):
|
def __init__(self, host, port, pubkey, privkey, request_initial_sync=False, network=None):
|
||||||
self.host = host
|
self.host = host
|
||||||
|
@ -606,7 +611,7 @@ class Peer(PrintError):
|
||||||
|
|
||||||
def send_message(self, msg):
|
def send_message(self, msg):
|
||||||
message_type, payload = decode_msg(msg)
|
message_type, payload = decode_msg(msg)
|
||||||
self.print_error("Sending '%s'"%message_type.upper(), payload)
|
self.print_error("Sending '%s'"%message_type.upper())
|
||||||
l = len(msg).to_bytes(2, 'big')
|
l = len(msg).to_bytes(2, 'big')
|
||||||
lc = aead_encrypt(self.sk, self.sn(), b'', l)
|
lc = aead_encrypt(self.sk, self.sn(), b'', l)
|
||||||
c = aead_encrypt(self.sk, self.sn(), b'', msg)
|
c = aead_encrypt(self.sk, self.sn(), b'', msg)
|
||||||
|
@ -937,12 +942,14 @@ class Peer(PrintError):
|
||||||
next_per_commitment_point=None,
|
next_per_commitment_point=None,
|
||||||
last_per_commitment_point=remote_per_commitment_point,
|
last_per_commitment_point=remote_per_commitment_point,
|
||||||
amount_sat=remote_amount,
|
amount_sat=remote_amount,
|
||||||
revocation_store=their_revocation_store
|
revocation_store=their_revocation_store,
|
||||||
|
next_htlc_id = 0
|
||||||
),
|
),
|
||||||
local_state=LocalState(
|
local_state=LocalState(
|
||||||
ctn = 0,
|
ctn = 0,
|
||||||
per_commitment_secret_seed=per_commitment_secret_seed,
|
per_commitment_secret_seed=per_commitment_secret_seed,
|
||||||
amount_sat=local_amount
|
amount_sat=local_amount,
|
||||||
|
next_htlc_id = 0
|
||||||
),
|
),
|
||||||
constraints=ChannelConstraints(capacity=funding_sat, feerate=local_feerate, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth)
|
constraints=ChannelConstraints(capacity=funding_sat, feerate=local_feerate, is_initiator=True, funding_txn_minimum_depth=funding_txn_minimum_depth)
|
||||||
)
|
)
|
||||||
|
@ -1040,17 +1047,22 @@ class Peer(PrintError):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return last_secret, this_point, next_point
|
return last_secret, this_point, next_point
|
||||||
|
their_revstore = chan.remote_state.revocation_store
|
||||||
sat = int(sat)
|
sat = int(sat)
|
||||||
cltv_expiry = wallet.get_local_height() + 9
|
await asyncio.sleep(1)
|
||||||
|
while not is_synced(wallet.network):
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
print("sleeping more")
|
||||||
|
cltv_expiry = wallet.get_local_height() + chan.remote_config.to_self_delay
|
||||||
assert sat > 0, "sat is not positive"
|
assert sat > 0, "sat is not positive"
|
||||||
amount_msat = sat * 1000
|
amount_msat = sat * 1000
|
||||||
|
|
||||||
assert type(self.pubkey) is bytes
|
assert type(self.pubkey) is bytes
|
||||||
hops_data = [OnionHopsDataSingle(OnionPerHop(chan.short_channel_id, amount_msat.to_bytes(8, "big"), cltv_expiry.to_bytes(4, "big")))]
|
hops_data = [OnionHopsDataSingle(OnionPerHop(chan.short_channel_id, amount_msat.to_bytes(8, "big"), cltv_expiry.to_bytes(4, "big")))]
|
||||||
associated_data = b""
|
associated_data = payment_hash
|
||||||
onion = new_onion_packet([self.pubkey], self.privkey, hops_data, associated_data)
|
onion = new_onion_packet([self.pubkey], os.urandom(32), hops_data, associated_data)
|
||||||
|
|
||||||
self.send_message(gen_msg("update_add_htlc", channel_id=chan.channel_id, id=0, cltv_expiry=cltv_expiry, amount_msat=amount_msat, payment_hash=payment_hash, onion_routing_packet=onion.to_bytes()))
|
self.send_message(gen_msg("update_add_htlc", channel_id=chan.channel_id, id=chan.local_state.next_htlc_id, cltv_expiry=cltv_expiry, amount_msat=amount_msat, payment_hash=payment_hash, onion_routing_packet=onion.to_bytes()))
|
||||||
|
|
||||||
their_local_htlc_pubkey = derive_pubkey(chan.remote_config.htlc_basepoint.pubkey, chan.remote_state.next_per_commitment_point)
|
their_local_htlc_pubkey = derive_pubkey(chan.remote_config.htlc_basepoint.pubkey, chan.remote_state.next_per_commitment_point)
|
||||||
their_remote_htlc_pubkey = derive_pubkey(chan.local_config.htlc_basepoint.pubkey, chan.remote_state.next_per_commitment_point)
|
their_remote_htlc_pubkey = derive_pubkey(chan.local_config.htlc_basepoint.pubkey, chan.remote_state.next_per_commitment_point)
|
||||||
|
@ -1074,28 +1086,14 @@ class Peer(PrintError):
|
||||||
|
|
||||||
self.send_message(gen_msg("commitment_signed", channel_id=chan.channel_id, signature=sig_64, num_htlcs=1, htlc_signature=htlc_sig))
|
self.send_message(gen_msg("commitment_signed", channel_id=chan.channel_id, signature=sig_64, num_htlcs=1, htlc_signature=htlc_sig))
|
||||||
|
|
||||||
last_secret, _, next_point = derive_and_incr()
|
|
||||||
self.send_message(gen_msg("revoke_and_ack",
|
|
||||||
channel_id=chan.channel_id,
|
|
||||||
per_commitment_secret=last_secret,
|
|
||||||
next_per_commitment_point=next_point))
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
revoke_and_ack_msg = await self.revoke_and_ack[chan.channel_id]
|
revoke_and_ack_msg = await self.revoke_and_ack[chan.channel_id]
|
||||||
finally:
|
finally:
|
||||||
del self.revoke_and_ack[chan.channel_id]
|
del self.revoke_and_ack[chan.channel_id]
|
||||||
|
|
||||||
# TODO check revoke_and_ack results
|
# TODO check revoke_and_ack results
|
||||||
next_per_commitment_point = revoke_and_ack_msg["next_per_commitment_point"]
|
|
||||||
|
|
||||||
try:
|
|
||||||
commitment_signed_msg = await self.commitment_signed[chan.channel_id]
|
|
||||||
finally:
|
|
||||||
del self.commitment_signed[chan.channel_id]
|
|
||||||
|
|
||||||
# TODO check commitment_signed results
|
|
||||||
|
|
||||||
last_secret, _, next_point = derive_and_incr()
|
last_secret, _, next_point = derive_and_incr()
|
||||||
|
their_revstore.add_next_entry(last_secret)
|
||||||
self.send_message(gen_msg("revoke_and_ack",
|
self.send_message(gen_msg("revoke_and_ack",
|
||||||
channel_id=chan.channel_id,
|
channel_id=chan.channel_id,
|
||||||
per_commitment_secret=last_secret,
|
per_commitment_secret=last_secret,
|
||||||
|
@ -1106,16 +1104,48 @@ class Peer(PrintError):
|
||||||
finally:
|
finally:
|
||||||
del self.update_fulfill_htlc[chan.channel_id]
|
del self.update_fulfill_htlc[chan.channel_id]
|
||||||
|
|
||||||
print("update_fulfill_htlc_msg", update_fulfill_htlc_msg)
|
# TODO use other fields too
|
||||||
|
next_per_commitment_point = revoke_and_ack_msg["next_per_commitment_point"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
commitment_signed_msg = await self.commitment_signed[chan.channel_id]
|
commitment_signed_msg = await self.commitment_signed[chan.channel_id]
|
||||||
finally:
|
finally:
|
||||||
del self.commitment_signed[chan.channel_id]
|
del self.commitment_signed[chan.channel_id]
|
||||||
|
|
||||||
# TODO send revoke_and_ack
|
# TODO check commitment_signed results
|
||||||
|
|
||||||
# TODO send commitment_signed
|
last_secret, _, next_point = derive_and_incr()
|
||||||
|
their_revstore.add_next_entry(last_secret)
|
||||||
|
self.send_message(gen_msg("revoke_and_ack",
|
||||||
|
channel_id=chan.channel_id,
|
||||||
|
per_commitment_secret=last_secret,
|
||||||
|
next_per_commitment_point=next_point))
|
||||||
|
|
||||||
|
bare_ctx = make_commitment_using_open_channel(chan, chan.remote_state.ctn + 2, False, next_per_commitment_point,
|
||||||
|
chan.remote_state.amount_sat + sat, chan.local_state.amount_sat - sat)
|
||||||
|
|
||||||
|
sig_64 = sign_and_get_sig_string(bare_ctx, chan.local_config, chan.remote_config)
|
||||||
|
|
||||||
|
self.send_message(gen_msg("commitment_signed", channel_id=chan.channel_id, signature=sig_64, num_htlcs=0))
|
||||||
|
try:
|
||||||
|
revoke_and_ack_msg = await self.revoke_and_ack[chan.channel_id]
|
||||||
|
finally:
|
||||||
|
del self.revoke_and_ack[chan.channel_id]
|
||||||
|
# TODO check revoke_and_ack results
|
||||||
|
|
||||||
|
return chan._replace(
|
||||||
|
local_state=chan.local_state._replace(
|
||||||
|
amount_sat=chan.local_state.amount_sat - sat,
|
||||||
|
next_htlc_id=chan.local_state.next_htlc_id + 1
|
||||||
|
),
|
||||||
|
remote_state=chan.remote_state._replace(
|
||||||
|
ctn=chan.remote_state.ctn + 2,
|
||||||
|
revocation_store=their_revstore,
|
||||||
|
last_per_commitment_point=next_per_commitment_point,
|
||||||
|
next_per_commitment_point=revoke_and_ack_msg["next_per_commitment_point"],
|
||||||
|
amount_sat=chan.remote_state.amount_sat + sat
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
async def receive_commitment_revoke_ack(self, chan, expected_received_sat, payment_preimage):
|
async def receive_commitment_revoke_ack(self, chan, expected_received_sat, payment_preimage):
|
||||||
def derive_and_incr():
|
def derive_and_incr():
|
||||||
|
@ -1143,8 +1173,10 @@ class Peer(PrintError):
|
||||||
finally:
|
finally:
|
||||||
del self.commitment_signed[channel_id]
|
del self.commitment_signed[channel_id]
|
||||||
|
|
||||||
|
assert len(self.unfulfilled_htlcs) == 1
|
||||||
htlc = self.unfulfilled_htlcs.pop()
|
htlc = self.unfulfilled_htlcs.pop()
|
||||||
htlc_id = int.from_bytes(htlc["id"], 'big')
|
htlc_id = int.from_bytes(htlc["id"], 'big')
|
||||||
|
assert htlc_id == chan.remote_state.next_htlc_id, (htlc_id, chan.remote_state.next_htlc_id)
|
||||||
cltv_expiry = int.from_bytes(htlc["cltv_expiry"], 'big')
|
cltv_expiry = int.from_bytes(htlc["cltv_expiry"], 'big')
|
||||||
# TODO verify sanity of their cltv expiry
|
# TODO verify sanity of their cltv expiry
|
||||||
amount_msat = int.from_bytes(htlc["amount_msat"], 'big')
|
amount_msat = int.from_bytes(htlc["amount_msat"], 'big')
|
||||||
|
@ -1264,7 +1296,8 @@ class Peer(PrintError):
|
||||||
revocation_store=their_revstore,
|
revocation_store=their_revstore,
|
||||||
last_per_commitment_point=remote_next_commitment_point,
|
last_per_commitment_point=remote_next_commitment_point,
|
||||||
next_per_commitment_point=revoke_and_ack_msg["next_per_commitment_point"],
|
next_per_commitment_point=revoke_and_ack_msg["next_per_commitment_point"],
|
||||||
amount_sat=chan.remote_state.amount_sat - expected_received_sat
|
amount_sat=chan.remote_state.amount_sat - expected_received_sat,
|
||||||
|
next_htlc_id=htlc_id + 1
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1275,7 +1308,7 @@ class Peer(PrintError):
|
||||||
|
|
||||||
def on_update_fulfill_htlc(self, payload):
|
def on_update_fulfill_htlc(self, payload):
|
||||||
channel_id = int.from_bytes(payload["channel_id"], 'big')
|
channel_id = int.from_bytes(payload["channel_id"], 'big')
|
||||||
self.update_fulfill_htlc[channel_id].set_reuslt(payload)
|
self.update_fulfill_htlc[channel_id].set_result(payload)
|
||||||
|
|
||||||
def on_update_fail_malformed_htlc(self, payload):
|
def on_update_fail_malformed_htlc(self, payload):
|
||||||
self.on_error(payload)
|
self.on_error(payload)
|
||||||
|
|
|
@ -128,14 +128,13 @@ if __name__ == "__main__":
|
||||||
addr = lndecode(sys.argv[6], expected_hrp="sb" if sys.argv[2] == "simnet" else "tb")
|
addr = lndecode(sys.argv[6], expected_hrp="sb" if sys.argv[2] == "simnet" else "tb")
|
||||||
payment_hash = addr.paymenthash
|
payment_hash = addr.paymenthash
|
||||||
amt = int(addr.amount * COIN)
|
amt = int(addr.amount * COIN)
|
||||||
print("amt", amt)
|
advanced_channel = await peer.pay(wallet, openchannel, amt, payment_hash)
|
||||||
await peer.pay(wallet, openchannel, amt, payment_hash)
|
else:
|
||||||
return
|
|
||||||
|
|
||||||
expected_received_sat = 200000
|
expected_received_sat = 200000
|
||||||
pay_req = lnencode(LnAddr(RHASH, amount=1/Decimal(COIN)*expected_received_sat, tags=[('d', 'one cup of coffee')]), peer.privkey[:32])
|
pay_req = lnencode(LnAddr(RHASH, amount=1/Decimal(COIN)*expected_received_sat, tags=[('d', 'one cup of coffee')]), peer.privkey[:32])
|
||||||
print("payment request", pay_req)
|
print("payment request", pay_req)
|
||||||
advanced_channel = await peer.receive_commitment_revoke_ack(openchannel, expected_received_sat, payment_preimage)
|
advanced_channel = await peer.receive_commitment_revoke_ack(openchannel, expected_received_sat, payment_preimage)
|
||||||
|
|
||||||
dumped = serialize_channels([advanced_channel])
|
dumped = serialize_channels([advanced_channel])
|
||||||
wallet.storage.put("channels", dumped)
|
wallet.storage.put("channels", dumped)
|
||||||
wallet.storage.write()
|
wallet.storage.write()
|
||||||
|
|
Loading…
Add table
Reference in a new issue