mirror of
https://github.com/LBRYFoundation/LBRY-Vault.git
synced 2025-09-19 08:59:50 +00:00
lnmsg.decode_msg: dict values for numbers are int, instead of BE bytes
Will be useful for TLVs where it makes sense to do the conversion in lnmsg, as it might be more complicated than just int.from_bytes().
This commit is contained in:
parent
4c10a830f3
commit
3a73f6ee5c
5 changed files with 75 additions and 68 deletions
|
@ -102,14 +102,14 @@ class Policy(NamedTuple):
|
||||||
def from_msg(payload: dict) -> 'Policy':
|
def from_msg(payload: dict) -> 'Policy':
|
||||||
return Policy(
|
return Policy(
|
||||||
key = payload['short_channel_id'] + payload['start_node'],
|
key = payload['short_channel_id'] + payload['start_node'],
|
||||||
cltv_expiry_delta = int.from_bytes(payload['cltv_expiry_delta'], "big"),
|
cltv_expiry_delta = payload['cltv_expiry_delta'],
|
||||||
htlc_minimum_msat = int.from_bytes(payload['htlc_minimum_msat'], "big"),
|
htlc_minimum_msat = payload['htlc_minimum_msat'],
|
||||||
htlc_maximum_msat = int.from_bytes(payload['htlc_maximum_msat'], "big") if 'htlc_maximum_msat' in payload else None,
|
htlc_maximum_msat = payload.get('htlc_maximum_msat', None),
|
||||||
fee_base_msat = int.from_bytes(payload['fee_base_msat'], "big"),
|
fee_base_msat = payload['fee_base_msat'],
|
||||||
fee_proportional_millionths = int.from_bytes(payload['fee_proportional_millionths'], "big"),
|
fee_proportional_millionths = payload['fee_proportional_millionths'],
|
||||||
message_flags = int.from_bytes(payload['message_flags'], "big"),
|
message_flags = int.from_bytes(payload['message_flags'], "big"),
|
||||||
channel_flags = int.from_bytes(payload['channel_flags'], "big"),
|
channel_flags = int.from_bytes(payload['channel_flags'], "big"),
|
||||||
timestamp = int.from_bytes(payload['timestamp'], "big")
|
timestamp = payload['timestamp'],
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -154,7 +154,7 @@ class NodeInfo(NamedTuple):
|
||||||
alias = alias.decode('utf8')
|
alias = alias.decode('utf8')
|
||||||
except:
|
except:
|
||||||
alias = ''
|
alias = ''
|
||||||
timestamp = int.from_bytes(payload['timestamp'], "big")
|
timestamp = payload['timestamp']
|
||||||
node_info = NodeInfo(node_id=node_id, features=features, timestamp=timestamp, alias=alias)
|
node_info = NodeInfo(node_id=node_id, features=features, timestamp=timestamp, alias=alias)
|
||||||
return node_info, peer_addrs
|
return node_info, peer_addrs
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ class ChannelDB(SqlDB):
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
for payload in payloads:
|
for payload in payloads:
|
||||||
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
||||||
timestamp = int.from_bytes(payload['timestamp'], "big")
|
timestamp = payload['timestamp']
|
||||||
if max_age and now - timestamp > max_age:
|
if max_age and now - timestamp > max_age:
|
||||||
expired.append(payload)
|
expired.append(payload)
|
||||||
continue
|
continue
|
||||||
|
@ -408,7 +408,7 @@ class ChannelDB(SqlDB):
|
||||||
known.append(payload)
|
known.append(payload)
|
||||||
# compare updates to existing database entries
|
# compare updates to existing database entries
|
||||||
for payload in known:
|
for payload in known:
|
||||||
timestamp = int.from_bytes(payload['timestamp'], "big")
|
timestamp = payload['timestamp']
|
||||||
start_node = payload['start_node']
|
start_node = payload['start_node']
|
||||||
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
short_channel_id = ShortChannelID(payload['short_channel_id'])
|
||||||
key = (start_node, short_channel_id)
|
key = (start_node, short_channel_id)
|
||||||
|
@ -673,7 +673,7 @@ class ChannelDB(SqlDB):
|
||||||
return
|
return
|
||||||
now = int(time.time())
|
now = int(time.time())
|
||||||
remote_update_decoded = decode_msg(remote_update_raw)[1]
|
remote_update_decoded = decode_msg(remote_update_raw)[1]
|
||||||
remote_update_decoded['timestamp'] = now.to_bytes(4, byteorder="big")
|
remote_update_decoded['timestamp'] = now
|
||||||
remote_update_decoded['start_node'] = node_id
|
remote_update_decoded['start_node'] = node_id
|
||||||
return Policy.from_msg(remote_update_decoded)
|
return Policy.from_msg(remote_update_decoded)
|
||||||
elif node_id == chan.get_local_pubkey(): # outgoing direction (from us)
|
elif node_id == chan.get_local_pubkey(): # outgoing direction (from us)
|
||||||
|
|
|
@ -218,13 +218,13 @@ class Channel(Logger):
|
||||||
short_channel_id=self.short_channel_id,
|
short_channel_id=self.short_channel_id,
|
||||||
channel_flags=channel_flags,
|
channel_flags=channel_flags,
|
||||||
message_flags=b'\x01',
|
message_flags=b'\x01',
|
||||||
cltv_expiry_delta=lnutil.NBLOCK_OUR_CLTV_EXPIRY_DELTA.to_bytes(2, byteorder="big"),
|
cltv_expiry_delta=lnutil.NBLOCK_OUR_CLTV_EXPIRY_DELTA,
|
||||||
htlc_minimum_msat=self.config[REMOTE].htlc_minimum_msat.to_bytes(8, byteorder="big"),
|
htlc_minimum_msat=self.config[REMOTE].htlc_minimum_msat,
|
||||||
htlc_maximum_msat=htlc_maximum_msat.to_bytes(8, byteorder="big"),
|
htlc_maximum_msat=htlc_maximum_msat,
|
||||||
fee_base_msat=lnutil.OUR_FEE_BASE_MSAT.to_bytes(4, byteorder="big"),
|
fee_base_msat=lnutil.OUR_FEE_BASE_MSAT,
|
||||||
fee_proportional_millionths=lnutil.OUR_FEE_PROPORTIONAL_MILLIONTHS.to_bytes(4, byteorder="big"),
|
fee_proportional_millionths=lnutil.OUR_FEE_PROPORTIONAL_MILLIONTHS,
|
||||||
chain_hash=constants.net.rev_genesis_bytes(),
|
chain_hash=constants.net.rev_genesis_bytes(),
|
||||||
timestamp=now.to_bytes(4, byteorder="big"),
|
timestamp=now,
|
||||||
)
|
)
|
||||||
sighash = sha256d(chan_upd[2 + 64:])
|
sighash = sha256d(chan_upd[2 + 64:])
|
||||||
sig = ecc.ECPrivkey(self.lnworker.node_keypair.privkey).sign(sighash, ecc.sig_string_from_r_and_s)
|
sig = ecc.ECPrivkey(self.lnworker.node_keypair.privkey).sign(sighash, ecc.sig_string_from_r_and_s)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import csv
|
import csv
|
||||||
import io
|
import io
|
||||||
from typing import Callable, Tuple, Any, Dict, List, Sequence, Union
|
from typing import Callable, Tuple, Any, Dict, List, Sequence, Union, Optional
|
||||||
|
|
||||||
|
|
||||||
class MalformedMsg(Exception):
|
class MalformedMsg(Exception):
|
||||||
|
@ -24,8 +24,7 @@ def _assert_can_read_at_least_n_bytes(fd: io.BytesIO, n: int) -> None:
|
||||||
raise UnexpectedEndOfStream(f"cur_pos={cur_pos}. end_pos={end_pos}. wants to read: {n}")
|
raise UnexpectedEndOfStream(f"cur_pos={cur_pos}. end_pos={end_pos}. wants to read: {n}")
|
||||||
|
|
||||||
|
|
||||||
# TODO return int when it makes sense
|
def _read_field(*, fd: io.BytesIO, field_type: str, count: int) -> Union[bytes, int]:
|
||||||
def _read_field(*, fd: io.BytesIO, field_type: str, count: int) -> bytes:
|
|
||||||
if not fd: raise Exception()
|
if not fd: raise Exception()
|
||||||
assert isinstance(count, int) and count >= 0, f"{count!r} must be non-neg int"
|
assert isinstance(count, int) and count >= 0, f"{count!r} must be non-neg int"
|
||||||
if count == 0:
|
if count == 0:
|
||||||
|
@ -35,10 +34,19 @@ def _read_field(*, fd: io.BytesIO, field_type: str, count: int) -> bytes:
|
||||||
type_len = 1
|
type_len = 1
|
||||||
elif field_type == 'u16':
|
elif field_type == 'u16':
|
||||||
type_len = 2
|
type_len = 2
|
||||||
|
assert count == 1, count
|
||||||
|
_assert_can_read_at_least_n_bytes(fd, type_len)
|
||||||
|
return int.from_bytes(fd.read(type_len), byteorder="big", signed=False)
|
||||||
elif field_type == 'u32':
|
elif field_type == 'u32':
|
||||||
type_len = 4
|
type_len = 4
|
||||||
|
assert count == 1, count
|
||||||
|
_assert_can_read_at_least_n_bytes(fd, type_len)
|
||||||
|
return int.from_bytes(fd.read(type_len), byteorder="big", signed=False)
|
||||||
elif field_type == 'u64':
|
elif field_type == 'u64':
|
||||||
type_len = 8
|
type_len = 8
|
||||||
|
assert count == 1, count
|
||||||
|
_assert_can_read_at_least_n_bytes(fd, type_len)
|
||||||
|
return int.from_bytes(fd.read(type_len), byteorder="big", signed=False)
|
||||||
# TODO tu16/tu32/tu64
|
# TODO tu16/tu32/tu64
|
||||||
elif field_type == 'chain_hash':
|
elif field_type == 'chain_hash':
|
||||||
type_len = 32
|
type_len = 32
|
||||||
|
@ -203,7 +211,8 @@ class LNSerializer:
|
||||||
try:
|
try:
|
||||||
field_count = int(field_count_str)
|
field_count = int(field_count_str)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
field_count = int.from_bytes(parsed[field_count_str], byteorder="big")
|
field_count = parsed[field_count_str]
|
||||||
|
assert isinstance(field_count, int)
|
||||||
#print(f">> count={field_count}. parsed={parsed}")
|
#print(f">> count={field_count}. parsed={parsed}")
|
||||||
try:
|
try:
|
||||||
parsed[field_name] = _read_field(fd=fd,
|
parsed[field_name] = _read_field(fd=fd,
|
||||||
|
|
|
@ -180,7 +180,7 @@ class Peer(Logger):
|
||||||
self.ordered_message_queues[chan_id].put_nowait((None, {'error':payload['data']}))
|
self.ordered_message_queues[chan_id].put_nowait((None, {'error':payload['data']}))
|
||||||
|
|
||||||
def on_ping(self, payload):
|
def on_ping(self, payload):
|
||||||
l = int.from_bytes(payload['num_pong_bytes'], 'big')
|
l = payload['num_pong_bytes']
|
||||||
self.send_message('pong', byteslen=l)
|
self.send_message('pong', byteslen=l)
|
||||||
|
|
||||||
def on_pong(self, payload):
|
def on_pong(self, payload):
|
||||||
|
@ -417,8 +417,8 @@ class Peer(Logger):
|
||||||
return ids
|
return ids
|
||||||
|
|
||||||
def on_reply_channel_range(self, payload):
|
def on_reply_channel_range(self, payload):
|
||||||
first = int.from_bytes(payload['first_blocknum'], 'big')
|
first = payload['first_blocknum']
|
||||||
num = int.from_bytes(payload['number_of_blocks'], 'big')
|
num = payload['number_of_blocks']
|
||||||
complete = bool(int.from_bytes(payload['complete'], 'big'))
|
complete = bool(int.from_bytes(payload['complete'], 'big'))
|
||||||
encoded = payload['encoded_short_ids']
|
encoded = payload['encoded_short_ids']
|
||||||
ids = self.decode_short_ids(encoded)
|
ids = self.decode_short_ids(encoded)
|
||||||
|
@ -541,27 +541,27 @@ class Peer(Logger):
|
||||||
)
|
)
|
||||||
payload = await self.wait_for_message('accept_channel', temp_channel_id)
|
payload = await self.wait_for_message('accept_channel', temp_channel_id)
|
||||||
remote_per_commitment_point = payload['first_per_commitment_point']
|
remote_per_commitment_point = payload['first_per_commitment_point']
|
||||||
funding_txn_minimum_depth = int.from_bytes(payload['minimum_depth'], 'big')
|
funding_txn_minimum_depth = payload['minimum_depth']
|
||||||
if funding_txn_minimum_depth <= 0:
|
if funding_txn_minimum_depth <= 0:
|
||||||
raise Exception(f"minimum depth too low, {funding_txn_minimum_depth}")
|
raise Exception(f"minimum depth too low, {funding_txn_minimum_depth}")
|
||||||
if funding_txn_minimum_depth > 30:
|
if funding_txn_minimum_depth > 30:
|
||||||
raise Exception(f"minimum depth too high, {funding_txn_minimum_depth}")
|
raise Exception(f"minimum depth too high, {funding_txn_minimum_depth}")
|
||||||
remote_dust_limit_sat = int.from_bytes(payload['dust_limit_satoshis'], byteorder='big')
|
remote_dust_limit_sat = payload['dust_limit_satoshis']
|
||||||
remote_reserve_sat = self.validate_remote_reserve(payload["channel_reserve_satoshis"], remote_dust_limit_sat, funding_sat)
|
remote_reserve_sat = self.validate_remote_reserve(payload["channel_reserve_satoshis"], remote_dust_limit_sat, funding_sat)
|
||||||
if remote_dust_limit_sat > remote_reserve_sat:
|
if remote_dust_limit_sat > remote_reserve_sat:
|
||||||
raise Exception(f"Remote Lightning peer reports dust_limit_sat > reserve_sat which is a BOLT-02 protocol violation.")
|
raise Exception(f"Remote Lightning peer reports dust_limit_sat > reserve_sat which is a BOLT-02 protocol violation.")
|
||||||
htlc_min = int.from_bytes(payload['htlc_minimum_msat'], 'big')
|
htlc_min = payload['htlc_minimum_msat']
|
||||||
if htlc_min > MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED:
|
if htlc_min > MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED:
|
||||||
raise Exception(f"Remote Lightning peer reports htlc_minimum_msat={htlc_min} mSAT," +
|
raise Exception(f"Remote Lightning peer reports htlc_minimum_msat={htlc_min} mSAT," +
|
||||||
f" which is above Electrums required maximum limit of that parameter ({MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED} mSAT).")
|
f" which is above Electrums required maximum limit of that parameter ({MAXIMUM_HTLC_MINIMUM_MSAT_ACCEPTED} mSAT).")
|
||||||
remote_max = int.from_bytes(payload['max_htlc_value_in_flight_msat'], 'big')
|
remote_max = payload['max_htlc_value_in_flight_msat']
|
||||||
if remote_max < MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED:
|
if remote_max < MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED:
|
||||||
raise Exception(f"Remote Lightning peer reports max_htlc_value_in_flight_msat at only {remote_max} mSAT" +
|
raise Exception(f"Remote Lightning peer reports max_htlc_value_in_flight_msat at only {remote_max} mSAT" +
|
||||||
f" which is below Electrums required minimum ({MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED} mSAT).")
|
f" which is below Electrums required minimum ({MINIMUM_MAX_HTLC_VALUE_IN_FLIGHT_ACCEPTED} mSAT).")
|
||||||
max_accepted_htlcs = int.from_bytes(payload["max_accepted_htlcs"], 'big')
|
max_accepted_htlcs = payload["max_accepted_htlcs"]
|
||||||
if max_accepted_htlcs > 483:
|
if max_accepted_htlcs > 483:
|
||||||
raise Exception("Remote Lightning peer reports max_accepted_htlcs > 483, which is a BOLT-02 protocol violation.")
|
raise Exception("Remote Lightning peer reports max_accepted_htlcs > 483, which is a BOLT-02 protocol violation.")
|
||||||
remote_to_self_delay = int.from_bytes(payload['to_self_delay'], byteorder='big')
|
remote_to_self_delay = payload['to_self_delay']
|
||||||
if remote_to_self_delay > MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED:
|
if remote_to_self_delay > MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED:
|
||||||
raise Exception(f"Remote Lightning peer reports to_self_delay={remote_to_self_delay}," +
|
raise Exception(f"Remote Lightning peer reports to_self_delay={remote_to_self_delay}," +
|
||||||
f" which is above Electrums required maximum ({MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED})")
|
f" which is above Electrums required maximum ({MAXIMUM_REMOTE_TO_SELF_DELAY_ACCEPTED})")
|
||||||
|
@ -647,9 +647,9 @@ class Peer(Logger):
|
||||||
# payload['channel_flags']
|
# payload['channel_flags']
|
||||||
if payload['chain_hash'] != constants.net.rev_genesis_bytes():
|
if payload['chain_hash'] != constants.net.rev_genesis_bytes():
|
||||||
raise Exception('wrong chain_hash')
|
raise Exception('wrong chain_hash')
|
||||||
funding_sat = int.from_bytes(payload['funding_satoshis'], 'big')
|
funding_sat = payload['funding_satoshis']
|
||||||
push_msat = int.from_bytes(payload['push_msat'], 'big')
|
push_msat = payload['push_msat']
|
||||||
feerate = int.from_bytes(payload['feerate_per_kw'], 'big')
|
feerate = payload['feerate_per_kw']
|
||||||
temp_chan_id = payload['temporary_channel_id']
|
temp_chan_id = payload['temporary_channel_id']
|
||||||
local_config = self.make_local_config(funding_sat, push_msat, REMOTE)
|
local_config = self.make_local_config(funding_sat, push_msat, REMOTE)
|
||||||
# for the first commitment transaction
|
# for the first commitment transaction
|
||||||
|
@ -674,11 +674,11 @@ class Peer(Logger):
|
||||||
first_per_commitment_point=per_commitment_point_first,
|
first_per_commitment_point=per_commitment_point_first,
|
||||||
)
|
)
|
||||||
funding_created = await self.wait_for_message('funding_created', temp_chan_id)
|
funding_created = await self.wait_for_message('funding_created', temp_chan_id)
|
||||||
funding_idx = int.from_bytes(funding_created['funding_output_index'], 'big')
|
funding_idx = funding_created['funding_output_index']
|
||||||
funding_txid = bh2u(funding_created['funding_txid'][::-1])
|
funding_txid = bh2u(funding_created['funding_txid'][::-1])
|
||||||
channel_id, funding_txid_bytes = channel_id_from_funding_tx(funding_txid, funding_idx)
|
channel_id, funding_txid_bytes = channel_id_from_funding_tx(funding_txid, funding_idx)
|
||||||
remote_balance_sat = funding_sat * 1000 - push_msat
|
remote_balance_sat = funding_sat * 1000 - push_msat
|
||||||
remote_dust_limit_sat = int.from_bytes(payload['dust_limit_satoshis'], byteorder='big') # TODO validate
|
remote_dust_limit_sat = payload['dust_limit_satoshis'] # TODO validate
|
||||||
remote_reserve_sat = self.validate_remote_reserve(payload['channel_reserve_satoshis'], remote_dust_limit_sat, funding_sat)
|
remote_reserve_sat = self.validate_remote_reserve(payload['channel_reserve_satoshis'], remote_dust_limit_sat, funding_sat)
|
||||||
remote_config = RemoteConfig(
|
remote_config = RemoteConfig(
|
||||||
payment_basepoint=OnlyPubkeyKeypair(payload['payment_basepoint']),
|
payment_basepoint=OnlyPubkeyKeypair(payload['payment_basepoint']),
|
||||||
|
@ -686,13 +686,13 @@ class Peer(Logger):
|
||||||
htlc_basepoint=OnlyPubkeyKeypair(payload['htlc_basepoint']),
|
htlc_basepoint=OnlyPubkeyKeypair(payload['htlc_basepoint']),
|
||||||
delayed_basepoint=OnlyPubkeyKeypair(payload['delayed_payment_basepoint']),
|
delayed_basepoint=OnlyPubkeyKeypair(payload['delayed_payment_basepoint']),
|
||||||
revocation_basepoint=OnlyPubkeyKeypair(payload['revocation_basepoint']),
|
revocation_basepoint=OnlyPubkeyKeypair(payload['revocation_basepoint']),
|
||||||
to_self_delay=int.from_bytes(payload['to_self_delay'], 'big'),
|
to_self_delay=payload['to_self_delay'],
|
||||||
dust_limit_sat=remote_dust_limit_sat,
|
dust_limit_sat=remote_dust_limit_sat,
|
||||||
max_htlc_value_in_flight_msat=int.from_bytes(payload['max_htlc_value_in_flight_msat'], 'big'), # TODO validate
|
max_htlc_value_in_flight_msat=payload['max_htlc_value_in_flight_msat'], # TODO validate
|
||||||
max_accepted_htlcs=int.from_bytes(payload['max_accepted_htlcs'], 'big'), # TODO validate
|
max_accepted_htlcs=payload['max_accepted_htlcs'], # TODO validate
|
||||||
initial_msat=remote_balance_sat,
|
initial_msat=remote_balance_sat,
|
||||||
reserve_sat = remote_reserve_sat,
|
reserve_sat = remote_reserve_sat,
|
||||||
htlc_minimum_msat=int.from_bytes(payload['htlc_minimum_msat'], 'big'), # TODO validate
|
htlc_minimum_msat=payload['htlc_minimum_msat'], # TODO validate
|
||||||
next_per_commitment_point=payload['first_per_commitment_point'],
|
next_per_commitment_point=payload['first_per_commitment_point'],
|
||||||
current_per_commitment_point=None,
|
current_per_commitment_point=None,
|
||||||
)
|
)
|
||||||
|
@ -718,8 +718,7 @@ class Peer(Logger):
|
||||||
chan.set_state(channel_states.OPENING)
|
chan.set_state(channel_states.OPENING)
|
||||||
self.lnworker.add_new_channel(chan)
|
self.lnworker.add_new_channel(chan)
|
||||||
|
|
||||||
def validate_remote_reserve(self, payload_field: bytes, dust_limit: int, funding_sat: int) -> int:
|
def validate_remote_reserve(self, remote_reserve_sat: int, dust_limit: int, funding_sat: int) -> int:
|
||||||
remote_reserve_sat = int.from_bytes(payload_field, 'big')
|
|
||||||
if remote_reserve_sat < dust_limit:
|
if remote_reserve_sat < dust_limit:
|
||||||
raise Exception('protocol violation: reserve < dust_limit')
|
raise Exception('protocol violation: reserve < dust_limit')
|
||||||
if remote_reserve_sat > funding_sat/100:
|
if remote_reserve_sat > funding_sat/100:
|
||||||
|
@ -768,8 +767,8 @@ class Peer(Logger):
|
||||||
f'(next_local_ctn={next_local_ctn}, '
|
f'(next_local_ctn={next_local_ctn}, '
|
||||||
f'oldest_unrevoked_remote_ctn={oldest_unrevoked_remote_ctn})')
|
f'oldest_unrevoked_remote_ctn={oldest_unrevoked_remote_ctn})')
|
||||||
msg = await self.wait_for_message('channel_reestablish', chan_id)
|
msg = await self.wait_for_message('channel_reestablish', chan_id)
|
||||||
their_next_local_ctn = int.from_bytes(msg["next_commitment_number"], 'big')
|
their_next_local_ctn = msg["next_commitment_number"]
|
||||||
their_oldest_unrevoked_remote_ctn = int.from_bytes(msg["next_revocation_number"], 'big')
|
their_oldest_unrevoked_remote_ctn = msg["next_revocation_number"]
|
||||||
their_local_pcp = msg.get("my_current_per_commitment_point")
|
their_local_pcp = msg.get("my_current_per_commitment_point")
|
||||||
their_claim_of_our_last_per_commitment_secret = msg.get("your_last_per_commitment_secret")
|
their_claim_of_our_last_per_commitment_secret = msg.get("your_last_per_commitment_secret")
|
||||||
self.logger.info(f'channel_reestablish ({chan.get_id_for_log()}): received channel_reestablish with '
|
self.logger.info(f'channel_reestablish ({chan.get_id_for_log()}): received channel_reestablish with '
|
||||||
|
@ -1005,7 +1004,7 @@ class Peer(Logger):
|
||||||
return msg_hash, node_signature, bitcoin_signature
|
return msg_hash, node_signature, bitcoin_signature
|
||||||
|
|
||||||
def on_update_fail_htlc(self, chan: Channel, payload):
|
def on_update_fail_htlc(self, chan: Channel, payload):
|
||||||
htlc_id = int.from_bytes(payload["id"], "big")
|
htlc_id = payload["id"]
|
||||||
reason = payload["reason"]
|
reason = payload["reason"]
|
||||||
self.logger.info(f"on_update_fail_htlc. chan {chan.short_channel_id}. htlc_id {htlc_id}")
|
self.logger.info(f"on_update_fail_htlc. chan {chan.short_channel_id}. htlc_id {htlc_id}")
|
||||||
chan.receive_fail_htlc(htlc_id, error_bytes=reason) # TODO handle exc and maybe fail channel (e.g. bad htlc_id)
|
chan.receive_fail_htlc(htlc_id, error_bytes=reason) # TODO handle exc and maybe fail channel (e.g. bad htlc_id)
|
||||||
|
@ -1083,7 +1082,7 @@ class Peer(Logger):
|
||||||
def on_update_fulfill_htlc(self, chan: Channel, payload):
|
def on_update_fulfill_htlc(self, chan: Channel, payload):
|
||||||
preimage = payload["payment_preimage"]
|
preimage = payload["payment_preimage"]
|
||||||
payment_hash = sha256(preimage)
|
payment_hash = sha256(preimage)
|
||||||
htlc_id = int.from_bytes(payload["id"], "big")
|
htlc_id = payload["id"]
|
||||||
self.logger.info(f"on_update_fulfill_htlc. chan {chan.short_channel_id}. htlc_id {htlc_id}")
|
self.logger.info(f"on_update_fulfill_htlc. chan {chan.short_channel_id}. htlc_id {htlc_id}")
|
||||||
chan.receive_htlc_settle(preimage, htlc_id) # TODO handle exc and maybe fail channel (e.g. bad htlc_id)
|
chan.receive_htlc_settle(preimage, htlc_id) # TODO handle exc and maybe fail channel (e.g. bad htlc_id)
|
||||||
self.lnworker.save_preimage(payment_hash, preimage)
|
self.lnworker.save_preimage(payment_hash, preimage)
|
||||||
|
@ -1103,10 +1102,10 @@ class Peer(Logger):
|
||||||
|
|
||||||
def on_update_add_htlc(self, chan: Channel, payload):
|
def on_update_add_htlc(self, chan: Channel, payload):
|
||||||
payment_hash = payload["payment_hash"]
|
payment_hash = payload["payment_hash"]
|
||||||
htlc_id = int.from_bytes(payload["id"], 'big')
|
htlc_id = payload["id"]
|
||||||
self.logger.info(f"on_update_add_htlc. chan {chan.short_channel_id}. htlc_id {htlc_id}")
|
self.logger.info(f"on_update_add_htlc. chan {chan.short_channel_id}. htlc_id {htlc_id}")
|
||||||
cltv_expiry = int.from_bytes(payload["cltv_expiry"], 'big')
|
cltv_expiry = payload["cltv_expiry"]
|
||||||
amount_msat_htlc = int.from_bytes(payload["amount_msat"], 'big')
|
amount_msat_htlc = payload["amount_msat"]
|
||||||
onion_packet = payload["onion_routing_packet"]
|
onion_packet = payload["onion_routing_packet"]
|
||||||
if chan.get_state() != channel_states.OPEN:
|
if chan.get_state() != channel_states.OPEN:
|
||||||
raise RemoteMisbehaving(f"received update_add_htlc while chan.get_state() != OPEN. state was {chan.get_state()}")
|
raise RemoteMisbehaving(f"received update_add_htlc while chan.get_state() != OPEN. state was {chan.get_state()}")
|
||||||
|
@ -1258,7 +1257,7 @@ class Peer(Logger):
|
||||||
self.maybe_send_commitment(chan)
|
self.maybe_send_commitment(chan)
|
||||||
|
|
||||||
def on_update_fee(self, chan: Channel, payload):
|
def on_update_fee(self, chan: Channel, payload):
|
||||||
feerate = int.from_bytes(payload["feerate_per_kw"], "big")
|
feerate = payload["feerate_per_kw"]
|
||||||
chan.update_fee(feerate, False)
|
chan.update_fee(feerate, False)
|
||||||
|
|
||||||
async def maybe_update_fee(self, chan: Channel):
|
async def maybe_update_fee(self, chan: Channel):
|
||||||
|
@ -1378,7 +1377,7 @@ class Peer(Logger):
|
||||||
while True:
|
while True:
|
||||||
# FIXME: the remote SHOULD send closing_signed, but some don't.
|
# FIXME: the remote SHOULD send closing_signed, but some don't.
|
||||||
cs_payload = await self.wait_for_message('closing_signed', chan.channel_id)
|
cs_payload = await self.wait_for_message('closing_signed', chan.channel_id)
|
||||||
their_fee = int.from_bytes(cs_payload['fee_satoshis'], 'big')
|
their_fee = cs_payload['fee_satoshis']
|
||||||
if their_fee > max_fee:
|
if their_fee > max_fee:
|
||||||
raise Exception(f'the proposed fee exceeds the base fee of the latest commitment transaction {is_local, their_fee, max_fee}')
|
raise Exception(f'the proposed fee exceeds the base fee of the latest commitment transaction {is_local, their_fee, max_fee}')
|
||||||
their_sig = cs_payload['signature']
|
their_sig = cs_payload['signature']
|
||||||
|
|
|
@ -57,46 +57,45 @@ class Test_LNRouter(TestCaseForTestnet):
|
||||||
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02cccccccccccccccccccccccccccccccc',
|
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02cccccccccccccccccccccccccccccccc',
|
||||||
'short_channel_id': bfh('0000000000000001'),
|
'short_channel_id': bfh('0000000000000001'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': b'\x00\x00', 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
self.assertEqual(cdb.num_channels, 1)
|
self.assertEqual(cdb.num_channels, 1)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
cdb.add_channel_announcement({'node_id_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
'bitcoin_key_1': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
'short_channel_id': bfh('0000000000000002'),
|
'short_channel_id': bfh('0000000000000002'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': b'\x00\x00', 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
cdb.add_channel_announcement({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
||||||
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
|
||||||
'short_channel_id': bfh('0000000000000003'),
|
'short_channel_id': bfh('0000000000000003'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': b'\x00\x00', 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02cccccccccccccccccccccccccccccccc', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
|
cdb.add_channel_announcement({'node_id_1': b'\x02cccccccccccccccccccccccccccccccc', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
|
||||||
'bitcoin_key_1': b'\x02cccccccccccccccccccccccccccccccc', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
|
'bitcoin_key_1': b'\x02cccccccccccccccccccccccccccccccc', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
|
||||||
'short_channel_id': bfh('0000000000000004'),
|
'short_channel_id': bfh('0000000000000004'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': b'\x00\x00', 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02dddddddddddddddddddddddddddddddd', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
cdb.add_channel_announcement({'node_id_1': b'\x02dddddddddddddddddddddddddddddddd', 'node_id_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
'bitcoin_key_1': b'\x02dddddddddddddddddddddddddddddddd', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
'bitcoin_key_1': b'\x02dddddddddddddddddddddddddddddddd', 'bitcoin_key_2': b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
|
||||||
'short_channel_id': bfh('0000000000000005'),
|
'short_channel_id': bfh('0000000000000005'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': b'\x00\x00', 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
cdb.add_channel_announcement({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
|
cdb.add_channel_announcement({'node_id_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'node_id_2': b'\x02dddddddddddddddddddddddddddddddd',
|
||||||
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
|
'bitcoin_key_1': b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'bitcoin_key_2': b'\x02dddddddddddddddddddddddddddddddd',
|
||||||
'short_channel_id': bfh('0000000000000006'),
|
'short_channel_id': bfh('0000000000000006'),
|
||||||
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
'chain_hash': BitcoinTestnet.rev_genesis_bytes(),
|
||||||
'len': b'\x00\x00', 'features': b''}, trusted=True)
|
'len': 0, 'features': b''}, trusted=True)
|
||||||
o = lambda i: i.to_bytes(8, "big")
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000001'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000001'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000001'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000001'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000002'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 99, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000002'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': o(99), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000002'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000002'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000003'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000003'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000003'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000003'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000004'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000004'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000004'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000004'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000005'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000005'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000005'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 999, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000005'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(999), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000006'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 99999999, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000006'), 'message_flags': b'\x00', 'channel_flags': b'\x00', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(99999999), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
cdb.add_channel_update({'short_channel_id': bfh('0000000000000006'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': 10, 'htlc_minimum_msat': 250, 'fee_base_msat': 100, 'fee_proportional_millionths': 150, 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': 0})
|
||||||
cdb.add_channel_update({'short_channel_id': bfh('0000000000000006'), 'message_flags': b'\x00', 'channel_flags': b'\x01', 'cltv_expiry_delta': o(10), 'htlc_minimum_msat': o(250), 'fee_base_msat': o(100), 'fee_proportional_millionths': o(150), 'chain_hash': BitcoinTestnet.rev_genesis_bytes(), 'timestamp': b'\x00\x00\x00\x00'})
|
|
||||||
path = path_finder.find_path_for_payment(b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 100000)
|
path = path_finder.find_path_for_payment(b'\x02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', 100000)
|
||||||
self.assertEqual([(b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', b'\x00\x00\x00\x00\x00\x00\x00\x03'),
|
self.assertEqual([(b'\x02bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', b'\x00\x00\x00\x00\x00\x00\x00\x03'),
|
||||||
(b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', b'\x00\x00\x00\x00\x00\x00\x00\x02'),
|
(b'\x02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee', b'\x00\x00\x00\x00\x00\x00\x00\x02'),
|
||||||
|
|
Loading…
Add table
Reference in a new issue