Skip to content

Commit c439589

Browse files
committed
pytest: generalize serialize_payload_tlv/serialize_payload_final_tlv
Put these in utils and make them a bit more powerful, so we can use them elsewhere. Signed-off-by: Rusty Russell <[email protected]>
1 parent 4d6481d commit c439589

File tree

2 files changed

+58
-66
lines changed

2 files changed

+58
-66
lines changed

tests/test_pay.py

Lines changed: 3 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
from fixtures import * # noqa: F401,F403
22
from fixtures import TEST_NETWORK
33
from pathlib import Path
4-
from io import BytesIO
54
from pyln.client import RpcError, Millisatoshi
65
from pyln.proto.onion import TlvPayload
76
from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND, FUNDAMOUNT, scid_to_int
87
from utils import (
98
wait_for, only_one, sync_blockheight, TIMEOUT,
10-
mine_funding_to_announce, first_scid
9+
mine_funding_to_announce, first_scid, serialize_payload_tlv, serialize_payload_final_tlv
1110
)
1211
import copy
1312
import os
1413
import pytest
1514
import random
1615
import re
1716
import string
18-
import struct
1917
import subprocess
2018
import time
2119
import unittest
@@ -2980,80 +2978,19 @@ def test_sendonion_rpc(node_factory):
29802978
first_hop = route[0]
29812979
blockheight = l1.rpc.getinfo()['blockheight']
29822980

2983-
def truncate_encode(i: int):
2984-
"""Encode a tu64 (or tu32 etc) value"""
2985-
ret = struct.pack("!Q", i)
2986-
while ret.startswith(b'\0'):
2987-
ret = ret[1:]
2988-
return ret
2989-
2990-
def serialize_payload_tlv(n):
2991-
block, tx, out = n['channel'].split('x')
2992-
2993-
payload = TlvPayload()
2994-
# BOLT #4:
2995-
# 1. type: 2 (`amt_to_forward`)
2996-
# 2. data:
2997-
# * [`tu64`:`amt_to_forward`]
2998-
b = BytesIO()
2999-
b.write(truncate_encode(int(n['amount_msat'])))
3000-
payload.add_field(2, b.getvalue())
3001-
# BOLT #4:
3002-
# 1. type: 4 (`outgoing_cltv_value`)
3003-
# 2. data:
3004-
# * [`tu32`:`outgoing_cltv_value`]
3005-
b = BytesIO()
3006-
b.write(truncate_encode(blockheight + n['delay']))
3007-
payload.add_field(4, b.getvalue())
3008-
# BOLT #4:
3009-
# 1. type: 6 (`short_channel_id`)
3010-
# 2. data:
3011-
# * [`short_channel_id`:`short_channel_id`]
3012-
b = BytesIO()
3013-
b.write(struct.pack("!Q", int(block) << 40 | int(tx) << 16 | int(out)))
3014-
payload.add_field(6, b.getvalue())
3015-
return payload.to_bytes().hex()
3016-
3017-
def serialize_payload_final_tlv(n, payment_secret: str):
3018-
payload = TlvPayload()
3019-
# BOLT #4:
3020-
# 1. type: 2 (`amt_to_forward`)
3021-
# 2. data:
3022-
# * [`tu64`:`amt_to_forward`]
3023-
b = BytesIO()
3024-
b.write(truncate_encode(int(n['amount_msat'])))
3025-
payload.add_field(2, b.getvalue())
3026-
# BOLT #4:
3027-
# 1. type: 4 (`outgoing_cltv_value`)
3028-
# 2. data:
3029-
# * [`tu32`:`outgoing_cltv_value`]
3030-
b = BytesIO()
3031-
b.write(truncate_encode(blockheight + n['delay']))
3032-
payload.add_field(4, b.getvalue())
3033-
# BOLT #4:
3034-
# 1. type: 8 (`payment_data`)
3035-
# 2. data:
3036-
# * [`32*byte`:`payment_secret`]
3037-
# * [`tu64`:`total_msat`]
3038-
b = BytesIO()
3039-
b.write(bytes.fromhex(payment_secret))
3040-
b.write(truncate_encode(int(n['amount_msat'])))
3041-
payload.add_field(8, b.getvalue())
3042-
return payload.to_bytes().hex()
3043-
30442981
# Need to shift the parameters by one hop
30452982
hops = []
30462983
for h, n in zip(route[:-1], route[1:]):
30472984
# We tell the node h about the parameters to use for n (a.k.a. h + 1)
30482985
hops.append({
30492986
"pubkey": h['id'],
3050-
"payload": serialize_payload_tlv(n)
2987+
"payload": serialize_payload_tlv(n['amount_msat'], n['delay'], n['channel'], blockheight).hex()
30512988
})
30522989

30532990
# The last hop has a special payload:
30542991
hops.append({
30552992
"pubkey": route[-1]['id'],
3056-
"payload": serialize_payload_final_tlv(route[-1], inv['payment_secret'])
2993+
"payload": serialize_payload_final_tlv(route[-1]['amount_msat'], route[-1]['delay'], route[-1]['amount_msat'], blockheight, inv['payment_secret']).hex()
30572994
})
30582995

30592996
onion = l1.rpc.createonion(hops=hops, assocdata=inv['payment_hash'])

tests/utils.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import bitstring
44
from pyln.client import Millisatoshi
55
from pyln.testing.utils import EXPERIMENTAL_DUAL_FUND, EXPERIMENTAL_SPLICING
6+
from pyln.proto.onion import TlvPayload
7+
import struct
68
import subprocess
79
import tempfile
810
import time
@@ -560,3 +562,56 @@ def write_dumb_template(outf, channels, propname, illegalvals=[]):
560562
nodemap[nodes[i]] = n
561563

562564
return outfile, nodemap
565+
566+
567+
def tu64_encode(i: int):
568+
"""Encode a tu64 (or tu32 etc) value"""
569+
ret = struct.pack("!Q", i)
570+
while ret.startswith(b'\0'):
571+
ret = ret[1:]
572+
return ret
573+
574+
575+
def serialize_payload_tlv(amount_msat, delay, next_channel, blockheight):
576+
"""Encode TLV onion payload for non-final hops, returns bytes"""
577+
block, tx, out = next_channel.split('x')
578+
579+
payload = TlvPayload()
580+
# BOLT #4:
581+
# 1. type: 2 (`amt_to_forward`)
582+
# 2. data:
583+
# * [`tu64`:`amt_to_forward`]
584+
payload.add_field(2, tu64_encode(int(amount_msat)))
585+
# BOLT #4:
586+
# 1. type: 4 (`outgoing_cltv_value`)
587+
# 2. data:
588+
# * [`tu32`:`outgoing_cltv_value`]
589+
payload.add_field(4, tu64_encode(blockheight + delay))
590+
# BOLT #4:
591+
# 1. type: 6 (`short_channel_id`)
592+
# 2. data:
593+
# * [`short_channel_id`:`short_channel_id`]
594+
payload.add_field(6, struct.pack("!Q", int(block) << 40 | int(tx) << 16 | int(out)))
595+
return payload.to_bytes()
596+
597+
598+
def serialize_payload_final_tlv(amount_msat, delay, total_msat, blockheight, payment_secret: str):
599+
"""Encode TLV onion payload for final hop, returns bytes"""
600+
payload = TlvPayload()
601+
# BOLT #4:
602+
# 1. type: 2 (`amt_to_forward`)
603+
# 2. data:
604+
# * [`tu64`:`amt_to_forward`]
605+
payload.add_field(2, tu64_encode(int(amount_msat)))
606+
# BOLT #4:
607+
# 1. type: 4 (`outgoing_cltv_value`)
608+
# 2. data:
609+
# * [`tu32`:`outgoing_cltv_value`]
610+
payload.add_field(4, tu64_encode(blockheight + delay))
611+
# BOLT #4:
612+
# 1. type: 8 (`payment_data`)
613+
# 2. data:
614+
# * [`32*byte`:`payment_secret`]
615+
# * [`tu64`:`total_msat`]
616+
payload.add_field(8, bytes.fromhex(payment_secret) + tu64_encode(int(total_msat)))
617+
return payload.to_bytes()

0 commit comments

Comments
 (0)